//这里都是一些常量
/**
 * 版本号
 * @static
 * @constant
 * @name VERSION
 * @type {string}
 */
var VERSION = "2.0.70";
/**
 * 判读window，标记浏览器环境，到时万一淘宝小程序内也有window，再改,这个貌似没有地方用到,用到了用自己方法取
 */
//@ts-ignore
// export const devicePixelRatio: number = window && (window.devicePixelRatio || 1) || my.getSystemInfoSync().pixelRatio;
/**
 * 获取设备号iOS  Android
 * 先判断浏览器环境设备号，没有就是小程序环境
 */
// export const osType: "ios" | "android" | "pc" = navigator && navigator.userAgent && (function () {
//     let n = navigator.userAgent.toLocaleLowerCase();
//     let reg1 = /android/;
//     let reg2 = /iphone|ipod|ipad/;
//     if (reg1.test(n)) {
//         return "android";
//     } else if (reg2.test(n)) {
//         return "ios"
//     } else {
//         return "pc";
//     }
// })()
//     //@ts-ignore //以后加了其他环境再改,现在除了web就是淘宝小程序
//     || my.getSystemInfoSync().platform.toLowerCase()
var PI = Math.PI;
var HalfPI = PI >> 1;
var PacPI = PI + HalfPI;
/**
 * @method cos
 * @private
 * @param {number} angle,弧度制
 * @return {number}
 */
function cos(angle) {
    switch (angle) {
        case HalfPI:
        case -PacPI:
            return 0;
        case PI:
        case -PI:
            return -1;
        case PacPI:
        case -HalfPI:
            return 0;
        default:
            return Math.cos(angle);
    }
}
/**
 * @method sin
 * @param {number} angle,弧度制
 * @return {number}
 */
function sin(angle) {
    switch (angle) {
        case HalfPI:
        case -PacPI:
            return 1;
        case PI:
        case -PI:
            return 0;
        case PacPI:
        case -HalfPI:
            return -1;
        default:
            return Math.sin(angle);
    }
}
/**
 * Two Pi.
 *
 * @static
 * @constant
 * @type {number}
 */
var PI_2 = PI * 2;
/**
 * Conversion factor for converting radians to degrees.
 * 弧度转角度
 * @static
 * @constant
 * @type {number}
 */
var RAD_TO_DEG = 180 / PI;
/**
 * Conversion factor for converting degrees to radians.
 * 角度转弧度
 * @static
 * @constant
 * @type {number}
 */
var DEG_TO_RAD = PI / 180;
/**
 * 渲染方式记录
 * @static
 * @constant
 * @name RENDERER_TYPE
 * @type {object}
 * @property {number} UNKNOWN - Unknown render type.
 * @property {number} WEBGL - WebGL render type.
 * @property {number} CANVAS - Canvas render type.
 */
var RENDERER_TYPE;
(function (RENDERER_TYPE) {
    RENDERER_TYPE[RENDERER_TYPE["UNKNOWN"] = 0] = "UNKNOWN";
    RENDERER_TYPE[RENDERER_TYPE["WEBGL"] = 1] = "WEBGL";
    RENDERER_TYPE[RENDERER_TYPE["CANVAS"] = 2] = "CANVAS";
})(RENDERER_TYPE || (RENDERER_TYPE = {}));
/**
 * 各种形状
 * @static
 * @constant
 * @name SHAPES
 * @type {object}
 * @property {number} POLY Polygon  多边形
 * @property {number} RECT Rectangle 矩形
 * @property {number} CIRC Circle 圆形
 * @property {number} ELIP Ellipse 椭圆
 * @property {number} RREC Rounded Rectangle 圆角矩形
 */
var SHAPES;
(function (SHAPES) {
    SHAPES[SHAPES["POLY"] = 0] = "POLY";
    SHAPES[SHAPES["RECT"] = 1] = "RECT";
    SHAPES[SHAPES["CIRC"] = 2] = "CIRC";
    SHAPES[SHAPES["ELIP"] = 3] = "ELIP";
    SHAPES[SHAPES["RREC"] = 4] = "RREC";
})(SHAPES || (SHAPES = {}));
/**
 * 着色器浮点精度
 * @static
 * @constant
 * @name PRECISION
 * @type {object}
 * @property {string} LOW='lowp'
 * @property {string} MEDIUM='mediump'
 * @property {string} HIGH='highp'
 */
var PRECISION;
(function (PRECISION) {
    PRECISION["LOW"] = "lowp";
    PRECISION["MEDIUM"] = "mediump";
    PRECISION["HIGH"] = "highp";
})(PRECISION || (PRECISION = {}));
/**
 * 文本渐变方式，以后用
 * @static
 * @constant
 * @name TEXT_GRADIENT
 * @type {object}
 * @property {number} LINEAR_VERTICAL 水平渐变
 * @property {number} LINEAR_HORIZONTAL 垂直渐变
 */
var TEXT_GRADIENT;
(function (TEXT_GRADIENT) {
    TEXT_GRADIENT[TEXT_GRADIENT["LINEAR_VERTICAL"] = 0] = "LINEAR_VERTICAL";
    TEXT_GRADIENT[TEXT_GRADIENT["LINEAR_HORIZONTAL"] = 1] = "LINEAR_HORIZONTAL";
})(TEXT_GRADIENT || (TEXT_GRADIENT = {}));
/**
 * 文本对齐方式  水平
 */
var TEXT_ALIGN;
(function (TEXT_ALIGN) {
    TEXT_ALIGN["CENTER"] = "center";
    TEXT_ALIGN["LEFT"] = "left";
    TEXT_ALIGN["RIGHT"] = "right";
})(TEXT_ALIGN || (TEXT_ALIGN = {}));
var VERTICAL_ALIGN;
(function (VERTICAL_ALIGN) {
    VERTICAL_ALIGN["MIDDLE"] = "middle";
    VERTICAL_ALIGN["UP"] = "up";
    VERTICAL_ALIGN["DOWN"] = "down";
    VERTICAL_ALIGN["TOP"] = "top";
    VERTICAL_ALIGN["BOTTOM"] = "bottom";
})(VERTICAL_ALIGN || (VERTICAL_ALIGN = {}));
/**
 * 文本类型，单行或多行
 */
var TEXT_lINETYPE;
(function (TEXT_lINETYPE) {
    TEXT_lINETYPE["SINGLE"] = "single";
    TEXT_lINETYPE["MULTI"] = "multi";
})(TEXT_lINETYPE || (TEXT_lINETYPE = {}));
/**
 * 画线时的对齐方式
 */
var LINE_ALIGNMENT;
(function (LINE_ALIGNMENT) {
    LINE_ALIGNMENT[LINE_ALIGNMENT["middle"] = 0.5] = "middle";
    LINE_ALIGNMENT[LINE_ALIGNMENT["outter"] = 1] = "outter";
    LINE_ALIGNMENT[LINE_ALIGNMENT["inner"] = 0] = "inner";
})(LINE_ALIGNMENT || (LINE_ALIGNMENT = {}));
/**
 * canvas线头
 */
var LINE_CAP;
(function (LINE_CAP) {
    LINE_CAP["BUTT"] = "butt";
    LINE_CAP["ROUND"] = "round";
    LINE_CAP["SQUARE"] = "square";
})(LINE_CAP || (LINE_CAP = {}));
/**
 * canvas线连接处
 */
var LINE_JOIN;
(function (LINE_JOIN) {
    LINE_JOIN["MITER"] = "miter";
    LINE_JOIN["ROUND"] = "round";
    LINE_JOIN["BEVEL"] = "bevel";
})(LINE_JOIN || (LINE_JOIN = {}));
/**
 * 混色模式，暂不支持使用
 * @static
 * @constant
 * @name BLEND_MODES
 * @type {object}
 * @property {number} NORMAL
 * @property {number} ADD
 * @property {number} MULTIPLY
 * @property {number} SCREEN
 * @property {number} OVERLAY
 * @property {number} DARKEN
 * @property {number} LIGHTEN
 * @property {number} COLOR_DODGE
 * @property {number} COLOR_BURN
 * @property {number} HARD_LIGHT
 * @property {number} SOFT_LIGHT
 * @property {number} DIFFERENCE
 * @property {number} EXCLUSION
 * @property {number} HUE
 * @property {number} SATURATION
 * @property {number} COLOR
 * @property {number} LUMINOSITY
 */
var BLEND_MODES;
(function (BLEND_MODES) {
    BLEND_MODES[BLEND_MODES["NORMAL"] = 0] = "NORMAL";
    BLEND_MODES[BLEND_MODES["ADD"] = 1] = "ADD";
    BLEND_MODES[BLEND_MODES["MULTIPLY"] = 2] = "MULTIPLY";
    BLEND_MODES[BLEND_MODES["SCREEN"] = 3] = "SCREEN";
    BLEND_MODES[BLEND_MODES["OVERLAY"] = 4] = "OVERLAY";
    BLEND_MODES[BLEND_MODES["DARKEN"] = 5] = "DARKEN";
    BLEND_MODES[BLEND_MODES["LIGHTEN"] = 6] = "LIGHTEN";
    BLEND_MODES[BLEND_MODES["COLOR_DODGE"] = 7] = "COLOR_DODGE";
    BLEND_MODES[BLEND_MODES["COLOR_BURN"] = 8] = "COLOR_BURN";
    BLEND_MODES[BLEND_MODES["HARD_LIGHT"] = 9] = "HARD_LIGHT";
    BLEND_MODES[BLEND_MODES["SOFT_LIGHT"] = 10] = "SOFT_LIGHT";
    BLEND_MODES[BLEND_MODES["DIFFERENCE"] = 11] = "DIFFERENCE";
    BLEND_MODES[BLEND_MODES["EXCLUSION"] = 12] = "EXCLUSION";
    BLEND_MODES[BLEND_MODES["HUE"] = 13] = "HUE";
    BLEND_MODES[BLEND_MODES["SATURATION"] = 14] = "SATURATION";
    BLEND_MODES[BLEND_MODES["COLOR"] = 15] = "COLOR";
    BLEND_MODES[BLEND_MODES["LUMINOSITY"] = 16] = "LUMINOSITY";
    BLEND_MODES[BLEND_MODES["NORMAL_NPM"] = 17] = "NORMAL_NPM";
    BLEND_MODES[BLEND_MODES["ADD_NPM"] = 18] = "ADD_NPM";
    BLEND_MODES[BLEND_MODES["SCREEN_NPM"] = 19] = "SCREEN_NPM";
    BLEND_MODES[BLEND_MODES["NONE"] = 20] = "NONE";
    BLEND_MODES[BLEND_MODES["SRC_OVER"] = 21] = "SRC_OVER";
    BLEND_MODES[BLEND_MODES["SRC_IN"] = 22] = "SRC_IN";
    BLEND_MODES[BLEND_MODES["SRC_OUT"] = 23] = "SRC_OUT";
    BLEND_MODES[BLEND_MODES["SRC_ATOP"] = 24] = "SRC_ATOP";
    BLEND_MODES[BLEND_MODES["DST_OVER"] = 25] = "DST_OVER";
    BLEND_MODES[BLEND_MODES["DST_IN"] = 26] = "DST_IN";
    BLEND_MODES[BLEND_MODES["DST_OUT"] = 27] = "DST_OUT";
    BLEND_MODES[BLEND_MODES["DST_ATOP"] = 28] = "DST_ATOP";
    BLEND_MODES[BLEND_MODES["ERASE"] = 29] = "ERASE";
    BLEND_MODES[BLEND_MODES["SUBTRACT"] = 30] = "SUBTRACT";
})(BLEND_MODES || (BLEND_MODES = {}));
/**
 * webgl的绘制模式枚举
 * @static
 * @constant
 * @name DRAW_MODES
 * @type {object}
 * @property {number} POINTS
 * @property {number} LINES
 * @property {number} LINE_LOOP
 * @property {number} LINE_STRIP
 * @property {number} TRIANGLES
 * @property {number} TRIANGLE_STRIP
 * @property {number} TRIANGLE_FAN
 */
var DRAW_MODES;
(function (DRAW_MODES) {
    DRAW_MODES[DRAW_MODES["POINTS"] = 0] = "POINTS";
    DRAW_MODES[DRAW_MODES["LINES"] = 1] = "LINES";
    DRAW_MODES[DRAW_MODES["LINE_LOOP"] = 2] = "LINE_LOOP";
    DRAW_MODES[DRAW_MODES["LINE_STRIP"] = 3] = "LINE_STRIP";
    DRAW_MODES[DRAW_MODES["TRIANGLES"] = 4] = "TRIANGLES";
    DRAW_MODES[DRAW_MODES["TRIANGLE_STRIP"] = 5] = "TRIANGLE_STRIP";
    DRAW_MODES[DRAW_MODES["TRIANGLE_FAN"] = 6] = "TRIANGLE_FAN";
})(DRAW_MODES || (DRAW_MODES = {}));
/**
 * 纹理的缩放模式
 * @static
 * @constant
 * @name SCALE_MODES
 * @type {object}
 * @property {number} LINEAR 线性插值光滑缩放
 * @property {number} NEAREST 使用临近像素缩放
 */
var SCALE_MODES;
(function (SCALE_MODES) {
    SCALE_MODES[SCALE_MODES["LINEAR"] = 0] = "LINEAR";
    SCALE_MODES[SCALE_MODES["NEAREST"] = 1] = "NEAREST";
})(SCALE_MODES || (SCALE_MODES = {}));
/**
 * 纹理的wrap mode
 * 非2的幂次纹理只能用CLAMP
 * 仅用于webgl模式
 * @static
 * @constant
 * @name WRAP_MODES
 * @type {object}
 * @property {number} CLAMP - The textures uvs are clamped
 * @property {number} REPEAT - The texture uvs tile and repeat
 * @property {number} MIRRORED_REPEAT - The texture uvs tile and repeat with mirroring
 */
var WRAP_MODES;
(function (WRAP_MODES) {
    WRAP_MODES[WRAP_MODES["CLAMP"] = 33071] = "CLAMP";
    WRAP_MODES[WRAP_MODES["REPEAT"] = 10497] = "REPEAT";
    WRAP_MODES[WRAP_MODES["MIRRORED_REPEAT"] = 33648] = "MIRRORED_REPEAT";
})(WRAP_MODES || (WRAP_MODES = {}));
/**
 * 查看类TextureGarbageCollector
 * @static
 * @constant
 * @name GC_MODES
 * @type {object}
 * @property {number} AUTO - 周期性自动回收
 * @property {number} MANUAL - 手动调用
 */
var GC_MODES;
(function (GC_MODES) {
    GC_MODES[GC_MODES["AUTO"] = 0] = "AUTO";
    GC_MODES[GC_MODES["MANUAL"] = 1] = "MANUAL";
})(GC_MODES || (GC_MODES = {}));

/******************************************************************************
Copyright (c) Microsoft Corporation.

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise */

var extendStatics = function(d, b) {
    extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
    return extendStatics(d, b);
};

function __extends(d, b) {
    if (typeof b !== "function" && b !== null)
        throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
    extendStatics(d, b);
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}

var __assign = function() {
    __assign = Object.assign || function __assign(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};

function __awaiter(thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
}

function __generator(thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
}

/** @deprecated */
function __spreadArrays() {
    for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
    for (var r = Array(s), k = 0, i = 0; i < il; i++)
        for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
            r[k] = a[j];
    return r;
}

/**
 * 基础对象，用于标记类名及唯一实例id
 * 只在引擎内部使用
 */
var HashObject = /** @class */ (function () {
    function HashObject() {
        this._instanceId = 0;
        this._instanceType = "HashObject";
        this._instanceId = HashObject._object_id++;
    }
    Object.defineProperty(HashObject.prototype, "instanceId", {
        /**
         * 实例唯一id
         * @property instanceId
         * @public
         * @since 1.0.0
         * @return {number}
         * @readonly
         */
        get: function () {
            return this._instanceId;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(HashObject.prototype, "instanceType", {
        /**
         * 实例类型
         * @property instanceType
         * @since 1.0.0
         * @public
         * @return {string}
         * @readonly
         */
        get: function () {
            return this._instanceType;
        },
        enumerable: false,
        configurable: true
    });
    HashObject._object_id = 0;
    return HashObject;
}());

/**
 * 事件类,引擎中一切事件的基类
 * @class Event
 * @extends AObject
 * @public
 * @since 1.0.0
 */
var Event = /** @class */ (function (_super) {
    __extends(Event, _super);
    /**
     * @method Event
     * @param {string} type 事件类型
     * @public
     * @since 1.0.0
     */
    function Event(type) {
        var _this = _super.call(this) || this;
        /**
         * 事件类型名
         * @property type
         * @type {string}
         * @public
         * @since 1.0.0
         */
        _this.type = "";
        /**
         * 触发此事件的对象
         * @property target
         * @public
         * @since 1.0.0
         * @type {any}
         */
        _this.target = null;
        /**
         * 随着事件一起附带的信息对象
         * 所有需要随事件一起发送的信息都可以放在此对象中
         * @property data
         * @public
         * @since 1.0.0
         * @type {any}
         * @default null
         */
        _this.data = null;
        /**
         * 是否阻止事件向下冒泡
         * @property _pd
         * @type {boolean}
         * @private
         * @since 1.0.0
         */
        _this._pd = false;
        _this._instanceType = "Event";
        _this.type = type;
        return _this;
    }
    /**
     * 防止对事件流中当前节点的后续节点中的所有事件侦听器进行处理。
     * 冒泡和捕获都有用
     * @method stopPropagation
     * @public
     * @since 2.0.0
     * @return {void}
     */
    Event.prototype.stopPropagation = function () {
        this._pd = true;
    };
    Event.prototype.destroy = function () {
        var s = this;
        s.target = null;
        s.data = null;
    };
    /**
     * 重置事件
     * @method reset
     * @param {string} type
     * @param target
     * @since 2.0.0
     * @return {void}
     * @public
     */
    Event.prototype.reset = function (type, target) {
        var s = this;
        s.target = target;
        s._pd = false;
        s.type = type;
        s.data = null; //最好加上，不然可能带上原来的数据
    };
    /**
     * 舞台尺寸发生变化时触发
     * @Event
     * @property RESIZE
     * @type {string}
     * @static
     * @public
     * @since 1.0.0
     */
    Event.RESIZE = "onResize";
    /**
     * Scroll组件滑动到开始位置事件
     * @property SCROLL_TO_HEAD
     * @static
     * @since 1.1.0
     * @type {string}
     */
    Event.SCROLL_TO_HEAD = "onScrollToHead";
    /**
     * Scroll组件停止滑动事件
     * @property SCROLL_STOP
     * @static
     * @since 1.1.0
     * @type {string}
     */
    Event.SCROLL_STOP = "onScrollStop";
    /**
     * Scroll组件开始滑动事件
     * @property SCROLL_START
     * @static
     * @since 1.1.0
     * @type {string}
     */
    Event.SCROLL_START = "onScrollStart";
    /**
     * Scroll组件滑动到结束位置事件
     * @property SCROLL_TO_END
     * @static
     * @since 1.1.0
     * @type {string}
     */
    Event.SCROLL_TO_END = "onScrollToEnd";
    /**
     * Scroll组件滚动时触发
     */
    Event.SCROLLING = "onScrolling";
    /**
     * 舞台初始化完成后会触发的事件
     * @property INIT_STAGE
     * @type {string}
     * @static
     * @public
     * @since 1.0.0
     */
    Event.INIT_STAGE = "onInitStage";
    /**
     * 显示对象加入到舞台事件
     * @Event
     * @type {string}
     * @static
     * @public
     * @since 1.0.0
     */
    Event.ADDED_TO_STAGE = "onAddedToStage";
    /**
     * 显示对象从舞台移出事件
     * @Event
     * @property REMOVED_FROM_STAGE
     * @type {string}
     * @static
     * @public
     * @since 1.0.0
     */
    Event.REMOVED_FROM_STAGE = "onRemovedFromStage";
    /**
     * 显示对象 循环帧事件
     * @Event
     * @property ENTER_FRAME
     * @type {string}
     * @static
     * @public
     * @since 1.0.0
     */
    Event.ENTER_FRAME = "onEnterFrame";
    /**
     * AnimationClip 播放完成事件
     * @Event
     * @property END_FRAME
     * @type {string}
     * @static
     * @public
     * @since 1.0.0
     */
    Event.END_FRAME = "onEndFrame";
    /**
     * 完成事件
     * @Event
     * @property COMPLETE
     * @type {string}
     * @static
     * @public
     * @since 1.0.0
     */
    Event.COMPLETE = "onComplete";
    /**
     * 加载过程事件
     * @Event
     * @property PROGRESS
     * @type {string}
     * @static
     * @public
     * @since 1.0.0
     */
    Event.PROGRESS = "onProgress";
    /**
     * 出错事件
     * @Event
     * @property ERROR
     * @type {string}
     * @static
     * @public
     * @since 1.0.0
     */
    Event.ERROR = "onError";
    /**
     * 输入框失去焦点事件
     * @Event
     * @property BLUR
     * @type {string}
     * @static
     * @public
     * @since 1.0.0
     */
    Event.BLUR = "onBlur";
    /**
     * 输入框聚焦事件
     * @Event
     * @property FOCUS
     * @type {string}
     * @static
     * @public
     * @since 1.0.0
     */
    Event.FOCUS = "onFocus";
    /**
     * 输入框输入事件
     * @Event
     * @property INPUT
     * @type {string}
     * @static
     * @public
     * @since 1.0.0
     */
    Event.INPUT = "onInput";
    return Event;
}(HashObject));

/**
 * 事件触发基类 功能简单
 * @class EventDispatcher
 * @extends HashObject
 * @public
 * @since 1.0.0
 */
var EventDispatcher = /** @class */ (function (_super) {
    __extends(EventDispatcher, _super);
    function EventDispatcher() {
        var _this = _super.call(this) || this;
        /**
         * 捕获阶段事件名
         */
        _this.eventTypes = {};
        /**
         * 冒泡阶段事件名
         */
        _this.eventTypes1 = {};
        _this._instanceType = "EventDispatcher";
        return _this;
    }
    /**
     * 获取鼠标事件数量
     * @method getMouseEventCount
     * @return {number}
     * @static
     * @private
     * @since 1.0.0
     * @param {string} type 获取事件类型，默认是所有
     */
    EventDispatcher.getMouseEventCount = function (type) {
        if (type === void 0) { type = ""; }
        var count = 0;
        if (type == "") {
            //返回所有鼠标事件数
            for (var item in EventDispatcher._MECO) {
                if (item.indexOf("onMouse") == 0) {
                    count += EventDispatcher._MECO[item];
                }
            }
        }
        else {
            if (EventDispatcher._MECO[type]) {
                count = EventDispatcher._MECO[type];
            }
        }
        return count;
    };
    /**
     * 给对象添加事件监听
     * @method addEventListener
     * @public
     * @since 1.0.0
     * @param {string} type 监听类形
     * @param {Function}listener 监听后的回调方法
     * @param {*}context listener中的this指向
     * @param {boolean} useCapture true 捕获阶段 false 冒泡阶段 默认 true
     * @example
     *      this.addEventListener("eventName",function(e){console.log(e);},this);
     */
    EventDispatcher.prototype.addEventListener = function (type, listener, context, useCapture) {
        if (useCapture === void 0) { useCapture = true; }
        if (!type) {
            throw new Error("type should not be empty");
        }
        if (!listener) {
            throw new Error("listener should not be empty");
        }
        var s = this;
        var eventTypes = s.eventTypes;
        if (!useCapture) {
            eventTypes = s.eventTypes1;
        }
        if (!eventTypes[type]) {
            eventTypes[type] = [];
        }
        // if (eventTypes[type].indexOf(listener) < 0) {
        //     eventTypes[type].unshift(listener);
        //     if (type.indexOf("onMouse") == 0) {
        //         s._changeMouseCount(type, true);
        //     }
        // }
        //改成EE的
        for (var i = 0, len = eventTypes[type].length; i < len; i++) {
            var ee = eventTypes[type][i];
            if (ee.fn === listener && ee.context === context) {
                console.warn("Same listener and context has been added before");
                return s;
            }
        }
        eventTypes[type].unshift(new EE(listener, context || s));
        if (type.indexOf("onMouse") == 0) {
            s._changeMouseCount(type, true);
        }
        return s;
    };
    /**
     * 监听一次
     * @param type
     * @param listener
     * @param context
     * @param useCapture
     */
    EventDispatcher.prototype.once = function (type, listener, context, useCapture) {
        if (useCapture === void 0) { useCapture = true; }
        if (!type) {
            throw new Error("type should not be empty");
        }
        if (!listener) {
            throw new Error("listener should not be empty");
        }
        var s = this;
        var eventTypes = s.eventTypes;
        if (!useCapture) {
            eventTypes = s.eventTypes1;
        }
        if (!eventTypes[type]) {
            eventTypes[type] = [];
        }
        //考虑是否要检查已添加过该事件
        eventTypes[type].unshift(new EE(listener, context || s, true));
        if (type.indexOf("onMouse") == 0) {
            s._changeMouseCount(type, true);
        }
        return s;
    };
    /**
     * 增加或删除相应mouse或touch侦听记数
     * @method _changeMouseCount
     * @private
     * @since 1.0.0
     * @param {string} type
     * @param {boolean} isAdd
     */
    EventDispatcher.prototype._changeMouseCount = function (type, isAdd) {
        var count = isAdd ? 1 : -1;
        if (!EventDispatcher._MECO[type]) {
            EventDispatcher._MECO[type] = 0;
        }
        EventDispatcher._MECO[type] += count;
        if (EventDispatcher._MECO[type] < 0) {
            EventDispatcher._MECO[type] = 0;
        }
        EventDispatcher._totalMEC += count;
    };
    /**
     * 广播侦听
     * @method dispatchEvent
     * @public
     * @since 1.0.0
     * @param {Event|string} event 广播所带的事件对象,如果传的是字符串则直接自动生成一个的事件对象,事件类型就是你传入进来的字符串的值
     * @param {Object} data 广播后跟着事件一起传过去的其他任信息,默认值为null，在传参中
     * @param {boolean} useCapture true 捕获阶段 false 冒泡阶段 默认 true
     * @return {boolean} 如果有收听者则返回true
     * @example
     *      var mySprite=new Sprite(),
     *          yourEvent=new Event("yourCustomerEvent");
     *       yourEvent.data='aaa';
     *       mySprite.addEventListener("yourCustomerEvent",function(e){
     *          console.log(e.data);
     *        })
     *       mySprite.dispatchEvent(yourEvent);
     */
    EventDispatcher.prototype.dispatchEvent = function (event, data, useCapture) {
        if (data === void 0) { data = null; }
        if (useCapture === void 0) { useCapture = true; }
        var s = this;
        if (typeof (event) == "string") {
            if (!s._defaultEvent) {
                s._defaultEvent = new Event(event);
            }
            else {
                s._defaultEvent.reset(event, s);
            }
            event = s._defaultEvent;
        }
        var listeners = s.eventTypes[event.type];
        if (!useCapture) {
            listeners = s.eventTypes1[event.type];
        }
        if (listeners) {
            var len = listeners.length;
            if (event.target == null) {
                event.target = s;
            }
            if (data != null) {
                event.data = data;
            }
            for (var i = len - 1; i >= 0; i--) {
                if (!event["_pd"]) {
                    if (listeners[i]) {
                        var listener = listeners[i];
                        var type = event.type; //防止call事件里触发其他事件导致event被修改；
                        listener.fn.call(listener.context, event);
                        //必须做单独指向，因为有可能出现上面的fn.里执行的就是removeEventListener，导致listeners[i]不存在
                        if (listener.once) {
                            s.removeEventListener(type /*event.type*/, listener.fn, listener.context, useCapture);
                        }
                        // listeners[i](event);
                    }
                    else {
                        //空的直接移除，
                        listeners.splice(i, 1);
                    }
                }
            }
            return true;
        }
        else {
            return false;
        }
    };
    /**
     * 是否有添加过此类形的侦听
     * @method hasEventListener
     * @public
     * @since 1.0.0
     * @param {string} type 侦听类形
     * @param {boolean} useCapture true 捕获阶段 false 冒泡阶段 默认 true
     * @return {boolean} 如果有则返回true
     */
    EventDispatcher.prototype.hasEventListener = function (type, useCapture) {
        if (useCapture === void 0) { useCapture = true; }
        var s = this;
        if (useCapture) {
            if (s.eventTypes[type] && s.eventTypes[type].length > 0) {
                return true;
            }
        }
        else {
            if (s.eventTypes1[type] && s.eventTypes1[type].length > 0) {
                return true;
            }
        }
        return false;
    };
    /**
     * 清除某一类型的所有事件
     * @param type
     * @param useCapture true 捕获阶段 false 冒泡阶段 默认 true
     * @return 返回自己
     */
    EventDispatcher.prototype.removeAllEventListenerByType = function (type, useCapture) {
        if (useCapture === void 0) { useCapture = true; }
        var s = this;
        if (useCapture) {
            if (s.eventTypes[type] && s.eventTypes[type].length > 0) {
                if (type.indexOf("onMouse") == 0) {
                    for (var j = 0; j < s.eventTypes[type].length; j++) {
                        s._changeMouseCount(type, false);
                    }
                }
                s.eventTypes[type] = [];
            }
        }
        else {
            if (s.eventTypes1[type] && s.eventTypes1[type].length > 0) {
                if (type.indexOf("onMouse") == 0) {
                    for (var j = 0; j < s.eventTypes1[type].length; j++) {
                        s._changeMouseCount(type, false);
                    }
                }
                s.eventTypes1[type] = [];
            }
        }
        return s;
    };
    /**
     * 移除对应类型的侦听
     * @method removeEventListener
     * @public
     * @since 1.0.0
     * @param {string} type 要移除的侦听类型
     * @param {Function} listener 及侦听时绑定的回调方法
     * @param context listener和context都相等的才移除，默认自身
     * @param {boolean} useCapture true 捕获阶段 false 冒泡阶段 默认 true
     */
    EventDispatcher.prototype.removeEventListener = function (type, listener, context, useCapture) {
        if (useCapture === void 0) { useCapture = true; }
        var s = this;
        var listeners = s.eventTypes[type];
        if (!useCapture) {
            listeners = s.eventTypes1[type];
        }
        if (listeners) {
            var len = listeners.length;
            var thisObject = context || s;
            for (var i = len - 1; i >= 0; i--) {
                if (listeners[i].fn === listener && listeners[i].context === thisObject) {
                    listeners.splice(i, 1);
                    if (type.indexOf("onMouse") == 0) {
                        s._changeMouseCount(type, false);
                    }
                }
                // if (listeners[i] === listener) {
                //     listeners.splice(i, 1);
                //     if (type.indexOf("onMouse") == 0) {
                //         s._changeMouseCount(type, false);
                //     }
                // }
            }
        }
        return s;
    };
    /**
     * 移除对象中所有的侦听
     * @method removeAllEventListener
     * @public
     * @since 1.0.0
     */
    EventDispatcher.prototype.removeAllEventListener = function () {
        var s = this;
        for (var type in s.eventTypes) {
            if (type.indexOf("onMouse") == 0) {
                for (var j = 0; j < s.eventTypes[type].length; j++) {
                    s._changeMouseCount(type, false);
                }
            }
        }
        for (var type in s.eventTypes1) {
            if (type.indexOf("onMouse") == 0) {
                for (var j = 0; j < s.eventTypes1[type].length; j++) {
                    s._changeMouseCount(type, false);
                }
            }
        }
        s.eventTypes1 = {};
        s.eventTypes = {};
    };
    EventDispatcher.prototype.destroy = function () {
        var s = this;
        s.removeAllEventListener();
        s.eventTypes = null;
        s.eventTypes1 = null;
    };
    /**
     * 全局的鼠标事件的监听数对象表，比如{"onMouseMove":9,"onMouseDown":7}
     * @property _MECO
     * @private
     * @since 1.0.0
     */
    EventDispatcher._MECO = {};
    /**
     * 所有鼠标事件的数量
     */
    EventDispatcher._totalMEC = 0;
    return EventDispatcher;
}(HashObject));
/**
 * 为了实现带入this和once
 * 暂不做回收处理，因为存在引用fn,context.内存销毁可能出问题
 * 如果非要作回收，回收时必须将fn,context置null；这样还有必要回收？
 */
var EE = /** @class */ (function () {
    function EE(fn, context, once) {
        if (once === void 0) { once = false; }
        this.fn = fn;
        this.context = context;
        this.once = once;
    }
    return EE;
}());

/**
 * @class Point
 * @extends HashObject
 * @since 1.0.0
 * @public
 */
var Point = /** @class */ (function (_super) {
    __extends(Point, _super);
    /**
     * 构造函数
     * @method Point
     * @public
     * @since 1.0.0
     * @param x
     * @param y
     */
    function Point(x, y) {
        if (x === void 0) { x = 0; }
        if (y === void 0) { y = 0; }
        var _this = _super.call(this) || this;
        /**
         * 水平坐标
         * @property x
         * @public
         * @since 1.0.0
         * @type{number}
         */
        _this.x = 0;
        /**
         * 垂直坐标
         * @property y
         * @since 1.0.0
         * @public
         * @type {number}
         */
        _this.y = 0;
        var s = _this;
        s._instanceType = "Point";
        s.x = x;
        s.y = y;
        return _this;
    }
    Point.prototype.destroy = function () { };
    /**
     * 求两点之间的距离
     * @method distance
     * @param args 可变参数 传两个参数的话就是两个Point类型 传四个参数的话分别是两个点的x y x y
     * @return {number}
     * @static
     */
    Point.distance = function () {
        var args = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            args[_i] = arguments[_i];
        }
        var len = args.length;
        if (len == 4) {
            return Math.sqrt((args[0] - args[2]) * (args[0] - args[2]) + (args[1] - args[3]) * (args[1] - args[3]));
        }
        else if (len == 2) {
            return Math.sqrt((args[0].x - args[1].x) * (args[0].x - args[1].x) + (args[0].y - args[1].y) * (args[0].y - args[1].y));
        }
    };
    Point.prototype.set = function (x, y) {
        this.x = x;
        this.y = y;
    };
    Point.prototype.copy = function (point) {
        this.x = point.x;
        this.y = point.y;
        return this;
    };
    return Point;
}(HashObject));

/**
 * 2维矩阵
 * @class Matrix
 * @extends HashObject
 * @public
 * @since 1.0.0
 */
var Matrix = /** @class */ (function (_super) {
    __extends(Matrix, _super);
    /**
     * 构造函数
     * @method Matrix
     * @param {number} a
     * @param {number} b
     * @param {number} c
     * @param {number} d
     * @param {number} tx
     * @param {number} ty
     * @public
     * @since 1.0.0
     */
    function Matrix(a, b, c, d, tx, ty) {
        if (a === void 0) { a = 1; }
        if (b === void 0) { b = 0; }
        if (c === void 0) { c = 0; }
        if (d === void 0) { d = 1; }
        if (tx === void 0) { tx = 0; }
        if (ty === void 0) { ty = 0; }
        var _this = _super.call(this) || this;
        /**
         * @property a
         * @type {number}
         * @public
         * @default 1
         * @since 1.0.0
         */
        _this.a = 1;
        /**
         * @property b
         * @public
         * @since 1.0.0
         * @type {number}
         */
        _this.b = 0;
        /**
         * @property c
         * @type {number}
         * @public
         * @since 1.0.0
         */
        _this.c = 0;
        /**
         * @property d
         * @type {number}
         * @public
         * @since 1.0.0
         */
        _this.d = 1;
        /**
         * @property tx
         * @type {number}
         * @public
         * @since 1.0.0
         */
        _this.tx = 0;
        /**
         * @property ty
         * @type {number}
         * @since 1.0.0
         * @public
         */
        _this.ty = 0;
        //数组形式
        _this.array = null;
        /**
         * 矩阵相乘
         * @method prepend
         * @public
         * @since 1.0.0
         * @param {Matrix} mtx
         */
        _this.prepend = function (mtx) {
            var s = this;
            var a = mtx.a;
            var b = mtx.b;
            var c = mtx.c;
            var d = mtx.d;
            var tx = mtx.tx;
            var ty = mtx.ty;
            var a1 = s.a;
            var c1 = s.c;
            var tx1 = s.tx;
            s.a = a * a1 + c * s.b;
            s.b = b * a1 + d * s.b;
            s.c = a * c1 + c * s.d;
            s.d = b * c1 + d * s.d;
            s.tx = a * tx1 + c * s.ty + tx;
            s.ty = b * tx1 + d * s.ty + ty;
            return this;
        };
        var s = _this;
        s._instanceType = "Matrix";
        s.a = a;
        s.b = b;
        s.c = c;
        s.d = d;
        s.tx = tx;
        s.ty = ty;
        return _this;
    }
    /**
     * 复制一个矩阵
     * @method clone
     * @since 1.0.0
     * @public
     * @return {Matrix}
     */
    Matrix.prototype.clone = function () {
        var s = this;
        return new Matrix(s.a, s.b, s.c, s.d, s.tx, s.ty);
    };
    /**
     * 复制一个矩阵的所有属性
     * @param matrix
     */
    Matrix.prototype.copy = function (matrix) {
        this.a = matrix.a;
        this.b = matrix.b;
        this.c = matrix.c;
        this.d = matrix.d;
        this.tx = matrix.tx;
        this.ty = matrix.ty;
        return this;
    };
    /**
     * 将一个点通过矩阵变换后的点，世界矩阵应用于局部坐标，转化为世界坐标
     * @method transformPoint
     * @param {number} x
     * @param {number} y
     * @param {Point} 默认为空，如果不为null，则返回的是Point就是此对象，如果为null，则返回来的Point是新建的对象
     * @return {Point}
     * @public
     * @since 1.0.0
     */
    Matrix.prototype.transformPoint = function (x, y, bp) {
        if (bp === void 0) { bp = null; }
        var s = this;
        if (!bp) {
            bp = new Point();
        }
        bp.x = x * s.a + y * s.c + s.tx;
        bp.y = x * s.b + y * s.d + s.ty;
        return bp;
    };
    /**
     * Get a new position with the inverse of the current transformation applied.
     * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input)
     * 用于世界坐标转化为局部坐标
     * @param {number} x
     * @param {number} y
     * @param {Point} 默认为空，如果不为null，则返回的是Point就是此对象，如果为null，则返回来的Point是新建的对象
     * @return {Point}
     */
    Matrix.prototype.transformPointInverse = function (x, y, bp) {
        if (bp === void 0) { bp = null; }
        if (!bp) {
            bp = new Point();
        }
        var id = 1 / ((this.a * this.d) + (this.c * -this.b));
        bp.x = (this.d * id * x) + (-this.c * id * y) + (((this.ty * this.c) - (this.tx * this.d)) * id);
        bp.y = (this.a * id * y) + (-this.b * id * x) + (((-this.ty * this.a) + (this.tx * this.b)) * id);
        return bp;
    };
    /**
     * 从一个矩阵里赋值给这个矩阵
     * @method setFrom
     * @param {Matrix} mtx
     * @public
     * @since 1.0.0
     */
    Matrix.prototype.setFrom = function (mtx) {
        var s = this;
        s.a = mtx.a;
        s.b = mtx.b;
        s.c = mtx.c;
        s.d = mtx.d;
        s.tx = mtx.tx;
        s.ty = mtx.ty;
    };
    /**
     * 将矩阵恢复成原始矩阵
     * @method identity
     * @public
     * @since 1.0.0
     */
    Matrix.prototype.identity = function () {
        var s = this;
        s.a = s.d = 1;
        s.b = s.c = s.tx = s.ty = 0;
    };
    /**
     * 反转一个矩阵
     * @method invert
     * @return {Matrix}
     * @since 1.0.0
     * @public
     */
    Matrix.prototype.invert = function () {
        var s = this;
        var a = s.a;
        var b = s.b;
        var c = s.c;
        var d = s.d;
        var tx = s.tx;
        var ty = s.ty;
        if (b == 0 && c == 0) {
            if (a == 0 || d == 0) {
                s.a = s.d = s.tx = s.ty = 0;
            }
            else {
                a = s.a = 1 / a;
                d = s.d = 1 / d;
                s.tx = -a * tx;
                s.ty = -d * ty;
            }
            return s;
        }
        var determinant = a * d - b * c;
        if (determinant == 0) {
            s.identity();
            return s;
        }
        determinant = 1 / determinant;
        var k = s.a = d * determinant;
        b = s.b = -b * determinant;
        c = s.c = -c * determinant;
        d = s.d = a * determinant;
        s.tx = -(k * tx + c * ty);
        s.ty = -(b * tx + d * ty);
        return s;
    };
    /**
     * 设置一个矩阵通过普通的显示对象的相关九大属性，锚点不影响坐标原点,暂时不用
     * @method createBox
     * @param {number} x
     * @param {number} y
     * @param {number} scaleX
     * @param {number} scaleY
     * @param {number} rotation 角度制
     * @param {number} skewX 角度制
     * @param {number} skewY 角度制
     * @param {number} ax
     * @param {number} ay
     * @since 1.0.0
     * @public
     */
    Matrix.prototype.createBox = function (x, y, scaleX, scaleY, rotation, skewX, skewY, ax, ay) {
        var s = this;
        if (rotation != 0) {
            skewX = skewY = rotation % 360;
        }
        else {
            skewX %= 360;
            skewY %= 360;
        }
        if ((skewX == 0) && (skewY == 0)) {
            s.a = scaleX;
            s.b = s.c = 0;
            s.d = scaleY;
        }
        else {
            skewX *= DEG_TO_RAD;
            skewY *= DEG_TO_RAD;
            var u = cos(skewX);
            var v = sin(skewX);
            if (skewX == skewY) {
                s.a = u * scaleX;
                s.b = v * scaleX;
            }
            else {
                s.a = cos(skewY) * scaleX;
                s.b = sin(skewY) * scaleX;
            }
            s.c = -v * scaleY;
            s.d = u * scaleY;
        }
        s.tx = x + ax - (ax * s.a + ay * s.c);
        s.ty = y + ay - (ax * s.b + ay * s.d);
    };
    /**
    * Appends the given Matrix to this Matrix.
    *
    * @param {Matrix} matrix - The matrix to append.
    * @return {Matrix} This matrix. Good for chaining method calls.
    */
    Matrix.prototype.append = function (matrix) {
        var a1 = this.a;
        var b1 = this.b;
        var c1 = this.c;
        var d1 = this.d;
        this.a = (matrix.a * a1) + (matrix.b * c1);
        this.b = (matrix.a * b1) + (matrix.b * d1);
        this.c = (matrix.c * a1) + (matrix.d * c1);
        this.d = (matrix.c * b1) + (matrix.d * d1);
        this.tx = (matrix.tx * a1) + (matrix.ty * c1) + this.tx;
        this.ty = (matrix.tx * b1) + (matrix.ty * d1) + this.ty;
        // return this;
    };
    /**
     * 判断两个矩阵是否相等
     * @method isEqual
     * @static
     * @public
     * @since 1.0.0
     * @param {Matrix} m1
     * @param {Matrix} m2
     * @return {boolean}
     */
    Matrix.isEqual = function (m1, m2) {
        return m1.tx == m2.tx && m1.ty == m2.ty && m1.a == m2.a && m1.b == m2.b && m1.c == m2.c && m1.d == m2.d;
    };
    Matrix.prototype.concat = function (mtx) {
        var s = this;
        var a = s.a, b = s.b, c = s.c, d = s.d, tx = s.tx, ty = s.ty;
        var ma = mtx.a, mb = mtx.b, mc = mtx.c, md = mtx.d, mx = mtx.tx, my = mtx.ty;
        s.a = a * ma + b * mc;
        s.b = a * mb + b * md;
        s.c = c * ma + d * mc;
        s.d = c * mb + d * md;
        s.tx = tx * ma + ty * mc + mx;
        s.ty = tx * mb + ty * md + my;
    };
    /**
     * 对矩阵应用旋转转换。
     * @method rotate
     * @param angle 弧度制
     * @since 1.0.3
     * @public
     */
    Matrix.prototype.rotate = function (angle) {
        var s = this;
        var sin = Math.sin(angle), cos = Math.cos(angle), a = s.a, b = s.b, c = s.c, d = s.d, tx = s.tx, ty = s.ty;
        s.a = a * cos - b * sin;
        s.b = a * sin + b * cos;
        s.c = c * cos - d * sin;
        s.d = c * sin + d * cos;
        s.tx = tx * cos - ty * sin;
        s.ty = tx * sin + ty * cos;
    };
    /**
     * 对矩阵应用缩放转换。
     * @method scale
     * @param {Number} sx 用于沿 x 轴缩放对象的乘数。
     * @param {Number} sy 用于沿 y 轴缩放对象的乘数。
     * @since 1.0.3
     * @public
     */
    Matrix.prototype.scale = function (sx, sy) {
        var s = this;
        s.a *= sx;
        s.d *= sy;
        s.c *= sx;
        s.b *= sy;
        s.tx *= sx;
        s.ty *= sy;
    };
    /**
     * 沿 x 和 y 轴平移矩阵，由 dx 和 dy 参数指定。
     * @method translate
     * @public
     * @since 1.0.3
     * @param {Number} dx 沿 x 轴向右移动的量（以像素为单位
     * @param {Number} dy 沿 y 轴向右移动的量（以像素为单位
     */
    Matrix.prototype.translate = function (dx, dy) {
        var s = this;
        s.tx += dx;
        s.ty += dy;
    };
    Matrix.prototype.set = function (a, b, c, d, tx, ty) {
        this.a = a;
        this.b = b;
        this.c = c;
        this.d = d;
        this.tx = tx;
        this.ty = ty;
        return this;
    };
    /**
     * 获得角度,角度制,
     * 其他的x,y,就是tx,ty
     * scale就是a,d
     * skew基本不用
     */
    Matrix.prototype.getRotation = function () {
        return Math.round(Math.atan2(this.b, this.a) * RAD_TO_DEG);
    };
    /**
     * 输出数组.与glsl中的mat3对应,注意行列主序执行transpose;
     * 参数与3d的区别很大
     * @param {boolean} transpose - 是否转置,默认false,glsl中传入需要true
     * @param {Float32Array} [out=new Float32Array(9)] - 输出数组,如不传使用自身的array
     * @return {number[]} 返回数组
     */
    Matrix.prototype.toArray = function (transpose, out) {
        if (transpose === void 0) { transpose = false; }
        if (!this.array) {
            this.array = new Float32Array(9);
        }
        var array = out || this.array;
        if (transpose) {
            array[0] = this.a;
            array[1] = this.b;
            array[2] = 0;
            array[3] = this.c;
            array[4] = this.d;
            array[5] = 0;
            array[6] = this.tx;
            array[7] = this.ty;
            array[8] = 1;
        }
        else {
            array[0] = this.a;
            array[1] = this.c;
            array[2] = this.tx;
            array[3] = this.b;
            array[4] = this.d;
            array[5] = this.ty;
            array[6] = 0;
            array[7] = 0;
            array[8] = 1;
        }
        return array;
    };
    /**
     * 从矩阵数据转成tansform的数据
     * @param transform
     */
    Matrix.prototype.decompose = function (transform) {
        var a = this.a;
        var b = this.b;
        var c = this.c;
        var d = this.d;
        //取斜切
        var skewX = -Math.atan2(-c, d);
        var skewY = Math.atan2(b, a);
        var delta = Math.abs(skewX + skewY);
        //斜切值和旋转不唯一，所以设定条件只取其一
        if (delta < 0.00001 || Math.abs(PI_2 - delta) < 0.00001) {
            transform.rotation = skewY;
            //考虑是否必要
            if (a < 0 && d >= 0) {
                transform.rotation += (transform.rotation <= 0) ? Math.PI : -Math.PI;
            }
            transform.skew.x = transform.skew.y = 0;
        }
        else {
            transform.rotation = 0;
            transform.skew.x = skewX;
            transform.skew.y = skewY;
        }
        //取缩放
        transform.scale.x = Math.sqrt((a * a) + (b * b));
        transform.scale.y = Math.sqrt((c * c) + (d * d));
        //取位置
        transform.position.x = this.tx;
        transform.position.y = this.ty;
        return transform;
    };
    Object.defineProperty(Matrix, "IDENTITY", {
        /**
         * 获取一个初始化矩阵，返回新的实例
         * @static
         * @const
         */
        get: function () {
            return new Matrix();
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Matrix, "TEMP_MATRIX", {
        /**
         * 获取一个临时矩阵，返回新的实例
         * @static
         * @const
         */
        get: function () {
            return new Matrix();
        },
        enumerable: false,
        configurable: true
    });
    Matrix.prototype.destroy = function () {
    };
    return Matrix;
}(HashObject));

/**
 * 动态可监控ObservablePoint类
 * @class
 */
var ObservablePoint = /** @class */ (function (_super) {
    __extends(ObservablePoint, _super);
    /**
     * @param {Function} cb - 值改变时的回调
     * @param {object} scope - 回调里的上下文this
     * @param {number} [x=0] - x
     * @param {number} [y=0] - y
     */
    function ObservablePoint(cb, scope, x, y) {
        if (x === void 0) { x = 0; }
        if (y === void 0) { y = 0; }
        var _this = _super.call(this) || this;
        var s = _this;
        s._instanceType = "ObservablePoint";
        _this._x = x;
        _this._y = y;
        _this.cb = cb;
        _this.scope = scope;
        return _this;
    }
    /**
     * 设置xy
     * @param {number} [x=0]
     * @param {number} [y=0]
     */
    ObservablePoint.prototype.set = function (x, y) {
        var _x = x || 0;
        var _y = y || 0;
        if (this._x !== _x || this._y !== _y) {
            this._x = _x;
            this._y = _y;
            this.cb.call(this.scope);
        }
    };
    /**
     * 从一个点复制xy
     *
     * @param {*} point 存在x,y属性的对象都行
     */
    ObservablePoint.prototype.copy = function (point) {
        if (this._x !== point.x || this._y !== point.y) {
            this._x = point.x;
            this._y = point.y;
            this.cb.call(this.scope);
        }
        return this;
    };
    Object.defineProperty(ObservablePoint.prototype, "x", {
        get: function () {
            return this._x;
        },
        set: function (value) {
            if (this._x !== value) {
                this._x = value;
                this.cb.call(this.scope);
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(ObservablePoint.prototype, "y", {
        get: function () {
            return this._y;
        },
        set: function (value) {
            if (this._y !== value) {
                this._y = value;
                this.cb.call(this.scope);
            }
        },
        enumerable: false,
        configurable: true
    });
    ObservablePoint.prototype.destroy = function () {
    };
    return ObservablePoint;
}(HashObject));

/**
 *
 * @class Rectangle
 * @extends HashObject
 * @public
 * @since 1.0.0
 */
var Rectangle = /** @class */ (function (_super) {
    __extends(Rectangle, _super);
    /**
     * 构造函数
     * @method Rectangle
     * @param {number} x
     * @param {number} y
     * @param {number} width
     * @param {number} height
     */
    function Rectangle(x, y, width, height) {
        if (x === void 0) { x = 0; }
        if (y === void 0) { y = 0; }
        if (width === void 0) { width = 0; }
        if (height === void 0) { height = 0; }
        var _this = _super.call(this) || this;
        /**
         * 矩形左上角的 x 坐标
         * @property x
         * @public
         * @since 1.0.0
         * @type{number}
         * @default 0
         */
        _this.x = 0;
        /**
         * 矩形左上角的 y 坐标
         * @property y
         * @public
         * @since 1.0.0
         * @type{number}
         * @default 0
         */
        _this.y = 0;
        /**
         * 矩形的宽度（以像素为单位）
         * @property width
         * @public
         * @since 1.0.0
         * @type{number}
         * @default 0
         */
        _this.width = 0;
        /**
         * 矩形的高度（以像素为单位）
         * @property height
         * @public
         * @since 1.0.0
         * @type{number}
         * @default 0
         */
        _this.height = 0;
        var s = _this;
        s._instanceType = "Rectangle";
        s.x = x;
        s.y = y;
        s.height = height;
        s.width = width;
        _this.type = SHAPES.RECT;
        return _this;
    }
    Rectangle.prototype.clear = function () {
        this.x = 0;
        this.y = 0;
        this.width = 0;
        this.height = 0;
    };
    Rectangle.prototype.copy = function (rect) {
        this.x = rect.x;
        this.y = rect.y;
        this.width = rect.width;
        this.height = rect.height;
        return this;
    };
    Rectangle.prototype.clone = function () {
        return new Rectangle(this.x, this.y, this.width, this.height);
    };
    Object.defineProperty(Rectangle.prototype, "left", {
        /**
         * 左边界
         */
        get: function () {
            return this.x;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Rectangle.prototype, "right", {
        /**
         * 右边界
         */
        get: function () {
            return this.x + this.width;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Rectangle.prototype, "top", {
        /**
         * 上边界
         */
        get: function () {
            return this.y;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Rectangle.prototype, "bottom", {
        /**
         * 下边界
         */
        get: function () {
            return this.y + this.height;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 判断一个点是否在矩形内包括边
     * @method isPointIn
     * @param {Point} point
     * @return {boolean}
     * @public
     * @since 1.0.0
     */
    Rectangle.prototype.isPointIn = function (point) {
        var s = this;
        return point.x >= s.x && point.x <= (s.x + s.width) && point.y >= s.y && point.y <= (s.y + s.height);
    };
    /**
     * Fits this rectangle around the passed one.
     *
     * @param {Rectangle} rectangle - The rectangle to fit.
     */
    Rectangle.prototype.fit = function (rectangle) {
        var x1 = Math.max(this.x, rectangle.x);
        var x2 = Math.min(this.x + this.width, rectangle.x + rectangle.width);
        var y1 = Math.max(this.y, rectangle.y);
        var y2 = Math.min(this.y + this.height, rectangle.y + rectangle.height);
        this.x = x1;
        this.width = Math.max(x2 - x1, 0);
        this.y = y1;
        this.height = Math.max(y2 - y1, 0);
    };
    /**
     * Pads the rectangle making it grow in all directions.
     *
     * @param {number} paddingX - The horizontal padding amount.
     * @param {number} [paddingY] - The vertical padding amount.
     */
    Rectangle.prototype.pad = function (paddingX, paddingY) {
        paddingX = paddingX || 0;
        paddingY = paddingY || ((paddingY !== 0) ? paddingX : 0);
        this.x -= paddingX;
        this.y -= paddingY;
        this.width += paddingX * 2;
        this.height += paddingY * 2;
    };
    /**
     * 将多个矩形合成为一个矩形,并将结果存到第一个矩形参数，并返回
     * @method createFromRects
     * @param {Rectangle} rect
     * @param {..arg} arg
     * @public
     * @since 1.0.0
     * @static
     */
    Rectangle.createFromRects = function () {
        var arg = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            arg[_i] = arguments[_i];
        }
        if (arg.length == 0) {
            return null;
        }
        else if (arg.length == 1) {
            return arg[0];
        }
        else {
            var rect = arg[0];
            var x = rect.x, y = rect.y, w = rect.width, h = rect.height, wx1 = void 0, wx2 = void 0, hy1 = void 0, hy2 = void 0;
            for (var i = 1; i < arg.length; i++) {
                //如果宽高为空，后续考虑是否xy需要占位;
                if (!arg[i].width && !arg[i].height)
                    continue;
                wx1 = x + w;
                hy1 = y + h;
                wx2 = arg[i].x + arg[i].width;
                hy2 = arg[i].y + arg[i].height;
                if (x > arg[i].x /*|| wx1 == 0*/ || (x == 0 && w == 0)) { //先去掉wx1和hy1==0判断,如果x为负的，w为正的，也可能0
                    x = arg[i].x;
                }
                if (y > arg[i].y /*|| hy1 == 0*/ || (y == 0 && h == 0)) { //待检查 TODO
                    y = arg[i].y;
                }
                if (wx1 < wx2) {
                    wx1 = wx2;
                }
                if (hy1 < hy2) {
                    hy1 = hy2;
                }
                rect.x = x;
                rect.y = y;
                rect.width = wx1 - x;
                rect.height = hy1 - y;
            }
            return rect;
        }
    };
    /**
     * 通过一系列点来生成一个矩形
     * 返回包含所有给定的点的最小矩形
     * @method createFromPoints
     * @static
     * @public
     * @since 1.0.0
     * @param {Point} p1
     * @param {..arg} ary
     * @return {Rectangle}
     */
    Rectangle.createFromPoints = function (rect) {
        var arg = [];
        for (var _i = 1; _i < arguments.length; _i++) {
            arg[_i - 1] = arguments[_i];
        }
        var x = arg[0].x, y = arg[0].y, w = arg[0].x, h = arg[0].y;
        for (var i = 1; i < arg.length; i++) {
            if (arg[i] == null)
                continue;
            if (x > arg[i].x) {
                x = arg[i].x;
            }
            if (y > arg[i].y) {
                y = arg[i].y;
            }
            if (w < arg[i].x) {
                w = arg[i].x;
            }
            if (h < arg[i].y) {
                h = arg[i].y;
            }
        }
        rect.x = x;
        rect.y = y;
        rect.width = w - x;
        rect.height = h - y;
        return rect;
    };
    /**
     * 通过顶点数据  [0,1,
     *               2,3,
     *               1,3,
     *               1,0]
     * @param rect
     * @param vertexData 一般为8长度
     */
    Rectangle.createFromVertexData = function (rect, vertexData, matrix) {
        var temP = new Point();
        var x = vertexData[0], y = vertexData[1], w = vertexData[0], h = vertexData[1];
        if (matrix) {
            matrix.transformPoint(x, y, temP);
            x = w = temP.x;
            y = h = temP.y;
        }
        for (var i = 2; i < vertexData.length; i += 2) {
            if (vertexData[i] == null)
                continue;
            temP.set(vertexData[i], vertexData[i + 1]);
            if (matrix)
                matrix.transformPoint(temP.x, temP.y, temP);
            if (x > temP.x)
                x = temP.x;
            if (y > temP.y)
                y = temP.y;
            if (w < temP.x)
                w = temP.x;
            if (h < temP.y)
                h = temP.y;
        }
        rect.x = x;
        rect.y = y;
        rect.width = w - x;
        rect.height = h - y;
        return rect;
    };
    /**
     * 通过两个点来确定一个矩形
     * @method createRectform2Point
     * @static
     * @param rect
     * @param p1
     * @param p2
     * @return
     */
    Rectangle.createRectfrom2Point = function (rect, p1, p2) {
        var x = p1.x, y = p1.y, w = p1.x, h = p1.y;
        if (x > p2.x) {
            x = p2.x;
        }
        if (y > p2.y) {
            y = p2.y;
        }
        if (w < p2.x) {
            w = p2.x;
        }
        if (h < p2.y) {
            h = p2.y;
        }
        rect.x = x, rect.y = y, rect.width = w - x, rect.height = h - y;
        return rect;
    };
    /**
     * 判读两个矩形是否相交
     * @method testRectCross
     * @public
     * @since 1.0.2
     * @param r1
     * @param r2
     * @return {boolean}
     */
    Rectangle.testRectCross = function (ra, rb) {
        var a_cx, a_cy; /* 第一个中心点*/
        var b_cx, b_cy; /* 第二个中心点*/
        a_cx = ra.x + (ra.width / 2);
        a_cy = ra.y + (ra.height / 2);
        b_cx = rb.x + (rb.width / 2);
        b_cy = rb.y + (rb.height / 2);
        return ((Math.abs(a_cx - b_cx) <= (ra.width / 2 + rb.width / 2)) && (Math.abs(a_cy - b_cy) <= (ra.height / 2 + rb.height / 2)));
    };
    Rectangle.prototype.destroy = function () {
    };
    return Rectangle;
}(HashObject));

/**
 * @class
 */
var Transform = /** @class */ (function (_super) {
    __extends(Transform, _super);
    function Transform() {
        var _this = _super.call(this) || this;
        var s = _this;
        s._instanceType = "Transform";
        _this.worldMatrix = new Matrix();
        _this.localMatrix = new Matrix();
        //初始为0
        _this._worldID = 0;
        _this._parentID = 0;
        _this.position = new ObservablePoint(_this.onChange, _this, 0, 0);
        _this.scale = new ObservablePoint(_this.onChange, _this, 1, 1);
        _this.anchor = new ObservablePoint(_this.onChange, _this, 0, 0);
        _this.skew = new ObservablePoint(_this.updateSkew, _this, 0, 0);
        _this._rotation = 0;
        _this._cx = 1; // cos rotation + skewY;
        _this._sx = 0; // sin rotation + skewY;
        _this._cy = 0; // cos rotation + Math.PI/2 - skewX;
        _this._sy = 1; // sin rotation + Math.PI/2 - skewX;
        //初始为0
        _this._localID = 0;
        _this._currentLocalID = 0;
        return _this;
    }
    /**
     * 任何属性更改
     * @private
     */
    Transform.prototype.onChange = function () {
        this._localID++;
    };
    /**
     * 当斜切改变时，先记录，优化计算
     * @private
     */
    Transform.prototype.updateSkew = function () {
        this._cx = cos(this._rotation + this.skew._y);
        this._sx = sin(this._rotation + this.skew._y);
        this._cy = -sin(this._rotation - this.skew._x); // cos, added PI/2
        this._sy = cos(this._rotation - this.skew._x); // sin, added PI/2
        this._localID++;
    };
    /**
     * 更新本地矩阵
     */
    Transform.prototype.updateLocalMatrix = function () {
        var lt = this.localMatrix;
        if (this._localID !== this._currentLocalID) {
            //根据基础属性计算本地矩阵
            lt.a = this._cx * this.scale._x;
            lt.b = this._sx * this.scale._x;
            lt.c = this._cy * this.scale._y;
            lt.d = this._sy * this.scale._y;
            //不改变位置原点，只改缩放和旋转中心点，+this.anchor._x
            lt.tx = this.position._x + this.anchor._x - ((this.anchor._x * lt.a) + (this.anchor._y * lt.c));
            lt.ty = this.position._y + this.anchor._y - ((this.anchor._x * lt.b) + (this.anchor._y * lt.d));
            this._currentLocalID = this._localID;
            //保证会更新世界坐标
            this._parentID = -1;
        }
    };
    /**
     * 更新世界矩阵,跟随父级修改
     * @param {Transform} parentTransform - 父级矩阵
     */
    Transform.prototype.updateWorldMatrix = function (parentTransform) {
        var lt = this.localMatrix;
        //先确定local是否需要更新
        if (this._localID !== this._currentLocalID) {
            //根据基础属性计算本地矩阵
            lt.a = this._cx * this.scale._x;
            lt.b = this._sx * this.scale._x;
            lt.c = this._cy * this.scale._y;
            lt.d = this._sy * this.scale._y;
            //不改变位置原点，只改缩放和旋转中心点，+this.anchor._x
            lt.tx = this.position._x + this.anchor._x - ((this.anchor._x * lt.a) + (this.anchor._y * lt.c));
            lt.ty = this.position._y + this.anchor._y - ((this.anchor._x * lt.b) + (this.anchor._y * lt.d));
            this._currentLocalID = this._localID;
            //保证会更新世界坐标
            this._parentID = -1;
        }
        //判断是否和父级更新的_worldID一致，或者都为-1(防止都设为-1的情况)去掉-1判断后TODO待测试
        if (this._parentID !== parentTransform._worldID /*|| parentTransform._worldID == -1*/) {
            // concat the parent matrix with the objects transform.
            var pt = parentTransform.worldMatrix;
            var wt = this.worldMatrix;
            wt.a = (lt.a * pt.a) + (lt.b * pt.c);
            wt.b = (lt.a * pt.b) + (lt.b * pt.d);
            wt.c = (lt.c * pt.a) + (lt.d * pt.c);
            wt.d = (lt.c * pt.b) + (lt.d * pt.d);
            wt.tx = (lt.tx * pt.a) + (lt.ty * pt.c) + pt.tx;
            wt.ty = (lt.tx * pt.b) + (lt.ty * pt.d) + pt.ty;
            // if (parentTransform._worldID == -1) {
            //     this._parentID = parentTransform._worldID = 0;
            // } else {
            //     this._parentID = parentTransform._worldID
            // }
            //修改自身worldId,保证子级会更新
            this._worldID++;
        }
    };
    Object.defineProperty(Transform.prototype, "rotation", {
        /**
         * 弧度制
         *
         * @member {number}
         */
        get: function () {
            return this._rotation;
        },
        set: function (value) {
            if (value === this._rotation)
                return;
            this._rotation = value;
            this.updateSkew();
        },
        enumerable: false,
        configurable: true
    });
    Transform.prototype.destroy = function () {
        this.worldMatrix = null;
        this.localMatrix = null;
        this.position = null;
        this.skew = null;
        this.scale = null;
        this.anchor = null;
    };
    return Transform;
}(HashObject));

var EnvType;
(function (EnvType) {
    /**
     * 淘宝小程序，不能头部adapter是因为引擎包并不打包在项目代码里，所以头部都需要，TODO，后续考虑单独为淘宝小程序打引擎包（加入adapter），然后引擎内部就干净了，load里也要肃清
     */
    EnvType["tb"] = "tb";
    /**
     * web环境
     */
    EnvType["web"] = "web";
    // /**
    //  * 字节helium环境，暂时废弃
    //  * 打包的时候，
    //  * 1、引擎一并打入，并且头部添加helium-adapter，基本和Web保持一致
    //  * 2、客户端先loadScript(helium-adapter.js)，再loadScript(引擎)，最后loadScript(项目代码)
    //  */
    // hel = "hel",
    /**
     * 头条，抖音小游戏
     * 需要先执行ttAdapter.js注入兼容的全局变量
     */
    EnvType["tt"] = "tt";
    /**
     * 微信小游戏
     * 需要先执行wxAdapter.js注入兼容的全局变量
     */
    EnvType["wx"] = "wx";
})(EnvType || (EnvType = {}));
var env = EnvType.web;
//如果是浏览器环境，声明个my为null，为了无声明不报错
if (window)
    window["my"] = null; //在用webview的小程序环境内，只要在小程序的sdk前加js就无所谓，
function getEnv() {
    return env;
}
/**
 * 设置运行环境，一般不需要调用，预留
 * 方法initedByTbCanvas会自行设置env为tb
 * @param e 环境
 */
function setEnv(e) {
    env = e;
}
/**
 * 创建一个离屏的canvas
 */
function createCanvas() {
    //@ts-ignore  先这么改把，以后再改TODO，Texture.WHITE有个自执行，所以在setEnv前就会执行web的链路，以后考虑兼容document
    // return document && document.createElement("canvas") || createTbOffscreenCanvas()//my._createOffscreenCanvas();
    //淘宝小程序环境
    if (getEnv() == "tb")
        return createTbOffscreenCanvas(); //my._createOffscreenCanvas();
    //web环境或其他环境，当作兼容过document的
    /*if (getEnv() == "web" || getEnv() == "hel" || getEnv() == "tt")*/ return document.createElement("canvas");
}
function createTbOffscreenCanvas() {
    //@ts-ignore
    var tbMy = my;
    if (!tbMy)
        return null;
    //不带_的先试试
    if (tbMy.createOffscreenCanvas) {
        //先试试不加参数是否有返回，再用加参数的，淘宝小部件2.0的好像必须加参数，否则返回空的
        return tbMy.createOffscreenCanvas() || tbMy.createOffscreenCanvas(3, 3);
    }
    //再用带_的
    return tbMy._createOffscreenCanvas() || tbMy._createOffscreenCanvas(3, 3);
}
/**
 * 临时记录的淘宝小程序的主canvas
 */
var tbCanvas;
/**
 * 淘宝小程序项目，拿到canvas先执行这个,修改当前环境
 * @param canvas
 */
function initedByTbCanvas(canvas) {
    tbCanvas = canvas;
    setEnv(EnvType.tb);
}
//兼容老版本，TODO废弃
function initedByCanvas(canvas) {
    console.warn("Function initedByCanvas will be abandoned soon,use function initedByTbCanvas instead");
    initedByTbCanvas(canvas);
}
/**
 * 销毁记录的tbCanvas，一般也没必要执行，
 * 尤其多页面的淘宝小程序，销毁的话，createImage会有问题
 */
function destroyTbCanvas() {
    tbCanvas = null;
}
//兼容老版本，TODO废弃
function destroyCanvasContent() {
    console.warn("Function destroyCanvasContent will be abandoned soon,use function destroyTbCanvas instead");
    destroyTbCanvas();
}
/**
 * 返回图片
 * @returns
 */
function createImage() {
    if (getEnv() == "tb") {
        if (tbCanvas)
            return tbCanvas.createImage();
        console.warn("TbMini inited canvas does not exist");
    }
    //当作兼容过Image的
    else {
        return new Image();
    }
}
/**
 * 尽量外部自行调用循环，不用引擎给的，即将废弃
 * @param callback
 * @returns
 */
function requestAnimationFrame(callback) {
    //淘宝小程序环境
    if (getEnv() == "tb") {
        if (tbCanvas)
            return tbCanvas.requestAnimationFrame(callback);
        console.warn("TbMini inited canvas does not exist");
    }
    //其他环境，当作兼容过的
    else {
        return requestAnimationFrame(callback);
    }
}
function cancelAnimationFrame(id) {
    //淘宝小程序环境
    if (getEnv() == "tb") {
        if (tbCanvas) {
            tbCanvas.cancelAnimationFrame(id);
            return;
        }
        console.warn("TbMini inited canvas does not exist");
    }
    //其他环境，当作兼容过的
    else {
        cancelAnimationFrame(id);
    }
}
var webglSupported;
/**
 * 判断是否支持webgl
 * @function isWebGLSupported
 * @return {boolean}
 */
function isWebGLSupported() {
    //淘宝环境直接返回true，否则找淘宝小程序解决，tt环境待测试，TODO
    if (getEnv() == "tb" || getEnv() == "tt" /*|| getEnv() == "hel"*/ || getEnv() == "wx")
        return true;
    //已经判断过了，直接返回
    if (webglSupported !== undefined)
        return webglSupported;
    //进入判断，加上低性能下是否使用webgl标识，pc上因为failIfMajorPerformanceCaveat设为true获取不到webgl一般是驱动问题
    var contextOptions = { stencil: true, failIfMajorPerformanceCaveat: true };
    try {
        if (!window["WebGLRenderingContext"]) {
            return false;
        }
        var canvas = createCanvas(); // document.createElement('canvas');
        var gl = canvas.getContext('webgl', contextOptions) || canvas.getContext('experimental-webgl', contextOptions);
        var success = !!(gl && gl["getContextAttributes"]().stencil);
        if (gl) {
            var loseContext = gl["getExtension"]('WEBGL_lose_context');
            if (loseContext) {
                loseContext.loseContext();
            }
        }
        gl = null;
        return webglSupported = success;
    }
    catch (e) {
        return webglSupported = false;
    }
}
//缓存的操作系统类型
var osType;
/**
 * 获取操作系统类型，"ios" | "android" | "pc";
 * @returns
 */
function getOsType() {
    //有就直接返回
    if (osType)
        return osType;
    //淘宝小程序
    if (getEnv() == "tb") {
        //@ts-ignore
        osType = my.getSystemInfoSync().platform.toLowerCase();
    }
    //如果是hel环境，直接取window上的
    // else if (getEnv() == "hel") {
    //     osType = window && window["osType"];
    // }
    else /*if (getEnv() == "web")*/ {
        osType = navigator && navigator.userAgent && (function () {
            var n = navigator.userAgent.toLocaleLowerCase();
            var reg1 = /android/;
            var reg2 = /iphone|ipod|ipad/;
            if (reg1.test(n)) {
                return "android";
            }
            else if (reg2.test(n)) {
                return "ios";
            }
            else {
                return "pc";
            }
        })() || null;
        //@ts-ignore 如果没取到，有可能环境还没切换，直接用老方法获取，或者直接给个提示
        if (!osType && my)
            osType = my.getSystemInfoSync().platform.toLowerCase();
    }
    return osType;
}
var devicePixelRatio;
/**
 * 获取屏幕像素比dpr，内部没有用到
 * @returns
 */
function getDevicePixelRatio() {
    if (devicePixelRatio)
        return devicePixelRatio;
    //淘宝小程序
    if (getEnv() == "tb") {
        //@ts-ignore
        devicePixelRatio = my.getSystemInfoSync().pixelRatio;
    }
    //其他正常判断吧
    else /*if (getEnv() == "web" || getEnv() == "hel")*/ {
        devicePixelRatio = window && (window.devicePixelRatio || 1);
        //@ts-ignore如果还没取到，环境切换有问题，用老方法
        if (!devicePixelRatio && my)
            devicePixelRatio = my.getSystemInfoSync().pixelRatio;
    }
    return devicePixelRatio;
}

/**
 * Bit twiddling hacks for JavaScript.
 *
 * Author: Mikola Lysenko
 *
 * Ported from Stanford bit twiddling hack library:
 *    http://graphics.stanford.edu/~seander/bithacks.html
 */
//Number of bits in an integer
var INT_BITS = 32;
//Constants
var INT_BITS1 = 32;
var INT_MAX = 0x7fffffff;
var INT_MIN = -1 << (INT_BITS - 1);
//Computes absolute value of integer
function abs(v) {
    var mask = v >> (INT_BITS - 1);
    return (v ^ mask) - mask;
}
//Computes minimum of integers x and y
function min(x, y) {
    return y ^ ((x ^ y) & -(x < y));
}
//Computes maximum of integers x and y
function max(x, y) {
    return x ^ ((x ^ y) & -(x < y));
}
//Checks if a number is a power of two
function isPow2(v) {
    return !(v & (v - 1)) && (!!v);
}
//Computes log base 2 of v
function log2(v) {
    //Ts报错，但实际可运行
    var r, shift;
    r = Number(v > 0xFFFF) << 4;
    v >>>= r;
    shift = Number(v > 0xFF) << 3;
    v >>>= shift;
    r |= shift;
    shift = Number(v > 0xF) << 2;
    v >>>= shift;
    r |= shift;
    shift = Number(v > 0x3) << 1;
    v >>>= shift;
    r |= shift;
    return r | (v >> 1);
}
//Computes log base 10 of v
function log10(v) {
    return (v >= 1000000000) ? 9 : (v >= 100000000) ? 8 : (v >= 10000000) ? 7 :
        (v >= 1000000) ? 6 : (v >= 100000) ? 5 : (v >= 10000) ? 4 :
            (v >= 1000) ? 3 : (v >= 100) ? 2 : (v >= 10) ? 1 : 0;
}
//Counts number of bits
function popCount(v) {
    v = v - ((v >>> 1) & 0x55555555);
    v = (v & 0x33333333) + ((v >>> 2) & 0x33333333);
    return ((v + (v >>> 4) & 0xF0F0F0F) * 0x1010101) >>> 24;
}
//Counts number of trailing zeros
function countTrailingZeros(v) {
    var c = 32;
    v &= -v;
    if (v)
        c--;
    if (v & 0x0000FFFF)
        c -= 16;
    if (v & 0x00FF00FF)
        c -= 8;
    if (v & 0x0F0F0F0F)
        c -= 4;
    if (v & 0x33333333)
        c -= 2;
    if (v & 0x55555555)
        c -= 1;
    return c;
}
//Rounds to next power of 2
function nextPow2(v) {
    v += v === 0;
    --v;
    v |= v >>> 1;
    v |= v >>> 2;
    v |= v >>> 4;
    v |= v >>> 8;
    v |= v >>> 16;
    return v + 1;
}
//Rounds down to previous power of 2
function prevPow2(v) {
    v |= v >>> 1;
    v |= v >>> 2;
    v |= v >>> 4;
    v |= v >>> 8;
    v |= v >>> 16;
    return v - (v >>> 1);
}
//Computes parity of word
function parity(v) {
    v ^= v >>> 16;
    v ^= v >>> 8;
    v ^= v >>> 4;
    v &= 0xf;
    return (0x6996 >>> v) & 1;
}
var REVERSE_TABLE = new Array(256);
(function (tab) {
    for (var i = 0; i < 256; ++i) {
        var v = i, r = i, s = 7;
        for (v >>>= 1; v; v >>>= 1) {
            r <<= 1;
            r |= v & 1;
            --s;
        }
        tab[i] = (r << s) & 0xff;
    }
})(REVERSE_TABLE);
//Reverse bits in a 32 bit word
function reverse(v) {
    return (REVERSE_TABLE[v & 0xff] << 24) |
        (REVERSE_TABLE[(v >>> 8) & 0xff] << 16) |
        (REVERSE_TABLE[(v >>> 16) & 0xff] << 8) |
        REVERSE_TABLE[(v >>> 24) & 0xff];
}
//Interleave bits of 2 coordinates with 16 bits.  Useful for fast quadtree codes
function interleave2(x, y) {
    x &= 0xFFFF;
    x = (x | (x << 8)) & 0x00FF00FF;
    x = (x | (x << 4)) & 0x0F0F0F0F;
    x = (x | (x << 2)) & 0x33333333;
    x = (x | (x << 1)) & 0x55555555;
    y &= 0xFFFF;
    y = (y | (y << 8)) & 0x00FF00FF;
    y = (y | (y << 4)) & 0x0F0F0F0F;
    y = (y | (y << 2)) & 0x33333333;
    y = (y | (y << 1)) & 0x55555555;
    return x | (y << 1);
}
//Extracts the nth interleaved component
function deinterleave2(v, n) {
    v = (v >>> n) & 0x55555555;
    v = (v | (v >>> 1)) & 0x33333333;
    v = (v | (v >>> 2)) & 0x0F0F0F0F;
    v = (v | (v >>> 4)) & 0x00FF00FF;
    v = (v | (v >>> 16)) & 0x000FFFF;
    return (v << 16) >> 16;
}
//Interleave bits of 3 coordinates, each with 10 bits.  Useful for fast octree codes
function interleave3(x, y, z) {
    x &= 0x3FF;
    x = (x | (x << 16)) & 4278190335;
    x = (x | (x << 8)) & 251719695;
    x = (x | (x << 4)) & 3272356035;
    x = (x | (x << 2)) & 1227133513;
    y &= 0x3FF;
    y = (y | (y << 16)) & 4278190335;
    y = (y | (y << 8)) & 251719695;
    y = (y | (y << 4)) & 3272356035;
    y = (y | (y << 2)) & 1227133513;
    x |= (y << 1);
    z &= 0x3FF;
    z = (z | (z << 16)) & 4278190335;
    z = (z | (z << 8)) & 251719695;
    z = (z | (z << 4)) & 3272356035;
    z = (z | (z << 2)) & 1227133513;
    return x | (z << 2);
}
//Extracts nth interleaved component of a 3-tuple
function deinterleave3(v, n) {
    v = (v >>> n) & 1227133513;
    v = (v | (v >>> 2)) & 3272356035;
    v = (v | (v >>> 4)) & 251719695;
    v = (v | (v >>> 8)) & 4278190335;
    v = (v | (v >>> 16)) & 0x3FF;
    return (v << 22) >> 22;
}
//Computes next combination in colexicographic order (this is mistakenly called nextPermutation on the bit twiddling hacks page)
function nextCombination(v) {
    var t = v | (v - 1);
    return (t + 1) | (((~t & -~t) - 1) >>> (countTrailingZeros(v) + 1));
}

/**
 * 记录的一些方法和设置，还有index都是会往引擎导的，所以内部方法尽量不导
 */
var nextUid = 0;
/**
 * 获得唯一id
 * @function uid
 * @return {number} 唯一的id
 */
function uid() {
    return ++nextUid;
}
var backupCanvasCtx;
/**
 * 各种使用需要的canvas
 * 比如取canvas上下文创建对象，渐变色等
 * 像素碰撞检测时
 * 淘宝小程序内不要用任何相关的先
 */
// export const backupCanvas: HTMLCanvasElement = createCanvas() //= document.createElement("canvas")
function getBackupCanvasCtx() {
    if (!backupCanvasCtx) {
        var canvas = createCanvas();
        canvas.width = 1;
        canvas.height = 1;
        backupCanvasCtx = canvas.getContext("2d");
    }
    return backupCanvasCtx;
}
/**
 * 创建渐变色
 * getGradientColor([0, 0, 300, 0], [[0, "#ff0000", 1],[0.5, "#00ff00", 1],[1, "#0000ff", 1]])
 * @param points 四个数字表示线性渐变参考createLinearGradient，六个数字表示径向渐变参考createRadialGradient
 * @param colors  [系数, #式颜色值, 透明度]的数组，比如[[0, "#ff0000", 1],[0.5, "#00ff00", 1],[1, "#0000ff", 1]]
 */
function getGradientColor(points, colors) {
    var colorObj;
    var ctx = getBackupCanvasCtx(); //backupCanvas.getContext("2d");
    if (points.length == 4) {
        colorObj = ctx.createLinearGradient(points[0], points[1], points[2], points[3]);
    }
    else {
        colorObj = ctx.createRadialGradient(points[0], points[1], points[2], points[3], points[4], points[5]);
    }
    for (var i = 0, l = colors.length; i < l; i++) {
        colorObj.addColorStop(colors[i][0], getRGBA(colors[i][1], colors[i][2]));
    }
    return colorObj;
}
/**
 * 创建重复纹理
 * @param image
 */
function getCanvasBitmapStyle(image) {
    var ctx = getBackupCanvasCtx(); //backupCanvas.getContext("2d");
    return ctx.createPattern(image, "repeat");
}
/**
 * 十六进制颜色转rgb数组
 * @function hex2rgb
 * @param {number} hex -转换的十六进制颜色
 * @param  {number[]} [out=[]] 输出数组，
 * @return {number[]} [R, G, B]颜色 每项范围0到1
 */
function hex2rgb$1(hex, out) {
    out = out || [];
    out[0] = ((hex >> 16) & 0xFF) / 255;
    out[1] = ((hex >> 8) & 0xFF) / 255;
    out[2] = (hex & 0xFF) / 255;
    return out;
}
/**
 * 十六进制颜色转字符串
 * 0xffffff转"#ffffff"
 * @function hex2string
 * @param {number} hex - 转换的十六进制颜色
 * @return {string} 输出的字符串颜色.
 */
function hex2string(hex) {
    hex = hex.toString(16);
    hex = '000000'.substr(0, 6 - hex.length) + hex;
    return "#" + hex;
}
/**
 * 字符串颜色转十六进制
 * "#ffffff"或"0xffffff"转0xffffff
 * @param {string} string 转换的字符串颜色
 * @return {number} 输出的颜色数值
 */
function string2hex(string) {
    if (string.indexOf("#") == 0) {
        string = string.replace("#", "0x");
    }
    return parseInt(string); //到时改成+号
}
/**
 * 数组[R, G, B]转换为十六进制数值
 * rgb范围时0到1，和着色器中的一致
 * @function rgb2hex
 * @param {number[]} rgb -数组
 * @return {number} 十六进制颜色
 */
function rgb2hex$1(rgb) {
    return (((rgb[0] * 255) << 16) + ((rgb[1] * 255) << 8) + (rgb[2] * 255 | 0));
}
/**
 * 通过字符串颜色值和一个透明度值生成RGBA值
 * 用于canvas的api，
 * @method getRGBA
 * @param {string} color 字符串的颜色值,如:#33ffee
 * @param {number} alpha 0-1区间的一个数据 0完全透明 1完全不透明
 * @return {string}
 */
function getRGBA(color, alpha) {
    if (color.indexOf("0x") == 0) {
        color = color.replace("0x", "#");
    }
    //暂没考虑#ff这种
    if (color.length < 7) {
        color = "#000000";
    }
    if (alpha != 1) {
        var r = parseInt("0x" + color.substr(1, 2));
        var g = parseInt("0x" + color.substr(3, 2));
        var b = parseInt("0x" + color.substr(5, 2));
        color = "rgba(" + r + "," + g + "," + b + "," + alpha + ")";
    }
    return color;
}
/**
 * 获取正负号标记
 * 0 +1 -1
 * @memberof utils
 * @function sign
 * @param {number} n
 * @returns {number}
 */
function sign(n) {
    if (n === 0)
        return 0;
    return n < 0 ? -1 : 1;
}
/**
 * 预乘十六进制颜色与透明度
 * 着色器只需传一个参数
 * @param tint
 * @param alpha
 */
function premultiplyTint(tint, alpha) {
    if (alpha === 1.0) {
        return (alpha * 255 << 24) + tint;
    }
    if (alpha === 0.0) {
        return 0;
    }
    var R = ((tint >> 16) & 0xFF);
    var G = ((tint >> 8) & 0xFF);
    var B = (tint & 0xFF);
    R = ((R * alpha) + 0.5) | 0;
    G = ((G * alpha) + 0.5) | 0;
    B = ((B * alpha) + 0.5) | 0;
    return (alpha * 255 << 24) + (R << 16) + (G << 8) + B;
}
/**
 * 贴图缓存
 * 对于链接网络图片，直接以url作为key，自动缓存
 * 对于图集，直接以小图命名作为key（所以避免重复名字，不是同一张图集里的命名也不能一致，否则覆盖）
 * 不自动缓存base64图片
 * @private
 */
var TextureCache = Object.create(null);
/**
 * 基础贴图缓存
 * 基本不会直接用，不缓存base64
 * @private
 */
var BaseTextureCache = Object.create(null);
/**
 * 记录TextureSheet，便于帧动画贴图数据查找，暂时不用
 */
// export const TextureSheetCache = Object.create(null);
/**
 * 销毁所有缓存的纹理和基础纹理
 * @function destroyTextureCache
 */
function destroyTextureCache() {
    var key;
    for (key in TextureCache) {
        TextureCache[key].destroy();
    }
    for (key in BaseTextureCache) {
        BaseTextureCache[key].destroy();
    }
}
/**
 * 移除所有缓存的纹理和基础纹理，但不销毁
 * @function clearTextureCache
 */
function clearTextureCache() {
    var key;
    for (key in TextureCache) {
        delete TextureCache[key];
    }
    for (key in BaseTextureCache) {
        delete BaseTextureCache[key];
    }
}
/**
 * 用于记录引擎全局属性记录，暂时没用到，考虑废弃
 * 除了引擎内部修改赋值，外部仅供读取
 */
// export const GlobalPro = {
//     /**
//      * 舞台渲染类型，
//      */
//     stageRenderType: RENDERER_TYPE,
//     /**
//      * 实际渲染分辨率
//      */
//     dpi: 1,
//     /**
//      * 图集间隙
//      */
//     padding: 2,
// }
/**
 * 从数组中移除元素
 * @param arr 原数组
 * @param startIdx 开始下标
 * @param removeCount 移除数量
 */
function removeItems(arr, startIdx, removeCount) {
    var i, length = arr.length;
    if (startIdx >= length || removeCount === 0) {
        return;
    }
    removeCount = (startIdx + removeCount > length ? length - startIdx : removeCount);
    var len = length - removeCount;
    for (i = startIdx; i < len; ++i) {
        arr[i] = arr[i + removeCount];
    }
    arr.length = len;
}
/**
 * 取符合范围的值
 * @param value
 * @param min
 * @param max
 */
function clamp(value, min, max) {
    return Math.max(min, Math.min(max, value));
}
/**
 * 将二进制数组转成Base64字符串
 * @param buff 前端的二进制缓冲区数组
 */
function ArrayBufferToBase64(buff) {
    var alph = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", enc = "", n, p, bits, d = new Uint8Array(buff);
    var len = buff.byteLength * 8;
    for (var offset = 0; offset < len; offset += 6) {
        n = (offset / 8) | 0;
        p = offset % 8;
        bits = ((d[n] || 0) << p) >> 2;
        if (p > 2) {
            bits |= (d[n + 1] || 0) >> (10 - p);
        }
        enc += alph.charAt(bits & 63);
    }
    enc += p == 4 ? "=" : p == 6 ? "==" : "";
    return enc;
}
/**
 * 解析八进制数组为字符串
 * @param array
 */
function decodeText(array) {
    if (typeof TextDecoder !== 'undefined') {
        return new TextDecoder().decode(array);
    }
    // Avoid the String.fromCharCode.apply(null, array) shortcut, which
    // throws a "maximum call stack size exceeded" error for large arrays.
    var s = '';
    for (var i = 0, il = array.length; i < il; i++) {
        // Implicitly assumes little-endian.
        s += String.fromCharCode(array[i]);
    }
    // Merges multi-byte utf-8 characters.
    return decodeURIComponent(escape(s));
}

/**
 * 二面体群，n=4，用于翻转四边形纹理，包括镜像
 * 暂时用于纹理的旋转90度
 */
var ux = [1, 1, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1, -1, -1, 0, 1];
var uy = [0, 1, 1, 1, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1, -1, -1];
var vx = [0, -1, -1, -1, 0, 1, 1, 1, 0, 1, 1, 1, 0, -1, -1, -1];
var vy = [1, 1, 0, -1, -1, -1, 0, 1, -1, -1, 0, 1, 1, 1, 0, -1];
var tempMatrices = [];
var mul = [];
// function signum(x) {
//     if (x < 0) {
//         return -1;
//     }
//     if (x > 0) {
//         return 1;
//     }
//     return 0;
// }
function init() {
    for (var i = 0; i < 16; i++) {
        var row = [];
        mul.push(row);
        for (var j = 0; j < 16; j++) {
            var _ux = sign((ux[i] * ux[j]) + (vx[i] * uy[j]));
            var _uy = sign((uy[i] * ux[j]) + (vy[i] * uy[j]));
            var _vx = sign((ux[i] * vx[j]) + (vx[i] * vy[j]));
            var _vy = sign((uy[i] * vx[j]) + (vy[i] * vy[j]));
            for (var k = 0; k < 16; k++) {
                if (ux[k] === _ux && uy[k] === _uy && vx[k] === _vx && vy[k] === _vy) {
                    row.push(k);
                    break;
                }
            }
        }
    }
    for (var i = 0; i < 16; i++) {
        var mat = new Matrix();
        mat.set(ux[i], uy[i], vx[i], vy[i], 0, 0);
        tempMatrices.push(mat);
    }
}
init();
/**
 * Implements Dihedral Group D_8, see [group D4]{@link http://mathworld.wolfram.com/DihedralGroupD4.html},
 * D8 is the same but with diagonals. Used for texture rotations.
 *
 * Vector xX(i), xY(i) is U-axis of sprite with rotation i
 * Vector yY(i), yY(i) is V-axis of sprite with rotation i
 * Rotations: 0 grad (0), 90 grad (2), 180 grad (4), 270 grad (6)
 * Mirrors: vertical (8), main diagonal (10), horizontal (12), reverse diagonal (14)
 * This is the small part of gameofbombs.com portal system. It works.
 *
 * @author Ivan @ivanpopelyshev
 * @class
 */
var GroupD8 = {
    E: 0,
    SE: 1,
    S: 2,
    SW: 3,
    W: 4,
    NW: 5,
    N: 6,
    NE: 7,
    MIRROR_VERTICAL: 8,
    MIRROR_HORIZONTAL: 12,
    uX: function (ind) { return ux[ind]; },
    uY: function (ind) { return uy[ind]; },
    vX: function (ind) { return vx[ind]; },
    vY: function (ind) { return vy[ind]; },
    inv: function (rotation) {
        if (rotation & 8) {
            return rotation & 15;
        }
        return (-rotation) & 7;
    },
    add: function (rotationSecond, rotationFirst) { return mul[rotationSecond][rotationFirst]; },
    sub: function (rotationSecond, rotationFirst) { return mul[rotationSecond][GroupD8.inv(rotationFirst)]; },
    /**
     * Adds 180 degrees to rotation. Commutative operation.
     *
     * @memberof GroupD8
     * @param {number} rotation - The number to rotate.
     * @returns {number} rotated number
     */
    rotate180: function (rotation) { return rotation ^ 4; },
    /**
     * Direction of main vector can be horizontal, vertical or diagonal.
     * Some objects work with vertical directions different.
     *
     * @memberof GroupD8
     * @param {number} rotation - The number to check.
     * @returns {boolean} Whether or not the direction is vertical
     */
    isVertical: function (rotation) { return (rotation & 3) === 2; },
    /**
     * @memberof GroupD8
     * @param {number} dx - TODO
     * @param {number} dy - TODO
     *
     * @return {number} TODO
     */
    byDirection: function (dx, dy) {
        if (Math.abs(dx) * 2 <= Math.abs(dy)) {
            if (dy >= 0) {
                return GroupD8.S;
            }
            return GroupD8.N;
        }
        else if (Math.abs(dy) * 2 <= Math.abs(dx)) {
            if (dx > 0) {
                return GroupD8.E;
            }
            return GroupD8.W;
        }
        else if (dy > 0) {
            if (dx > 0) {
                return GroupD8.SE;
            }
            return GroupD8.SW;
        }
        else if (dx > 0) {
            return GroupD8.NE;
        }
        return GroupD8.NW;
    },
    /**
     * Helps sprite to compensate texture packer rotation.
     *
     * @memberof GroupD8
     * @param {Matrix} matrix - sprite world matrix
     * @param {number} rotation - The rotation factor to use.
     * @param {number} tx - sprite anchoring
     * @param {number} ty - sprite anchoring
     */
    matrixAppendRotationInv: function (matrix, rotation, tx, ty) {
        if (tx === void 0) { tx = 0; }
        if (ty === void 0) { ty = 0; }
        // Packer used "rotation", we use "inv(rotation)"
        var mat = tempMatrices[GroupD8.inv(rotation)];
        mat.tx = tx;
        mat.ty = ty;
        matrix.append(mat);
    },
};

/**
 * 基础显示对象抽象类
 * @class
 * @extends EventDispatcher
 */
var DisplayObject = /** @class */ (function (_super) {
    __extends(DisplayObject, _super);
    function DisplayObject() {
        var _this = _super.call(this) || this;
        /**
         * 是否可响应鼠标事件
         */
        _this.mouseEnable = true;
        _this._instanceType = "DisplayObject";
        _this.tempDisplayObjectParent = null;
        _this.transform = new Transform();
        _this._alpha = 1;
        _this.visible = true;
        _this.renderable = true;
        _this.parent = null;
        _this._worldAlpha = 1;
        //滤镜相关，都置null
        _this.filterArea = null;
        _this._filters = null;
        _this._enabledFilters = null;
        _this._localBoundsSelf = new Rectangle();
        _this._bounds = new Rectangle();
        _this._boundsID = 0;
        _this._lastBoundsID = -1;
        _this._mask = null;
        _this.destroyed = false;
        return _this;
    }
    Object.defineProperty(DisplayObject.prototype, "filters", {
        get: function () { return this._filters && this._filters.slice(); },
        set: function (value) { this._filters = value && value.slice(); },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(DisplayObject.prototype, "_tempDisplayObjectParent", {
        /**
         * @private
         * @member {DisplayObject}
         */
        get: function () {
            if (this.tempDisplayObjectParent === null) {
                this.tempDisplayObjectParent = new DisplayObject();
            }
            return this.tempDisplayObjectParent;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 更新矩阵
     */
    DisplayObject.prototype.updateTransform = function () {
        this.transform.updateWorldMatrix(this.parent.transform);
        //更新透明度
        this._worldAlpha = this.alpha * this.parent._worldAlpha;
    };
    /**
     * 点击碰撞测试,就是舞台上的一个point是否在显示对象内,在则返回该对象，不在则返回null
     * 对于那些不是继承container，而直接继承displayObject的不用重写，如Bitmap
     * @method hitTestPoint
     * @public
     * @since 1.0.0
     * @param {Point} point 需要碰到的坐标点
     * @param {boolean} isMouseEvent 是否是鼠标事件调用此方法,一般都为true
     * @return {DisplayObject}
     */
    DisplayObject.prototype.hitTestPoint = function (point, isMouseEvent) {
        if (isMouseEvent === void 0) { isMouseEvent = false; }
        var s = this;
        if (!s.visible)
            return null;
        if (isMouseEvent && !s.mouseEnable)
            return null;
        if (!isMouseEvent) {
            //如果不是系统调用则不考虑这个点是从全局来的，只认为这个点就是当前要碰撞测试同级别下的坐标点
            if (s._localBoundsSelf.isPointIn(point)) {
                return s;
            }
        }
        else {
            if (s._localBoundsSelf.isPointIn(s.globalToLocal(point, DisplayObject._bp))) {
                return s;
            }
        }
        return null;
    };
    /**
     * 递归更新矩阵方法
     */
    DisplayObject.prototype._recursivePostUpdateTransform = function () {
        if (this.parent) {
            this.parent._recursivePostUpdateTransform();
            this.transform.updateWorldMatrix(this.parent.transform);
        }
        else {
            this.transform.updateWorldMatrix(this._tempDisplayObjectParent.transform);
        }
    };
    /**
     * 获取全局的包围盒，变形后的
     * @param {boolean} skipUpdate - 是否递归至父级的更新，默认false
     * @param {Rectangle} rect - 可选，返回的包围盒数据，不传会用固定临时对象
     * @return {Rectangle} 包围盒
     */
    DisplayObject.prototype.getBounds = function (skipUpdate, rect) {
        if (skipUpdate === void 0) { skipUpdate = false; }
        if (rect === void 0) { rect = DisplayObject.temBounds; }
        //先把父级的都变换
        if (!skipUpdate) {
            if (!this.parent) {
                this.parent = this._tempDisplayObjectParent;
                this.updateTransform();
                this.parent = null;
            }
            else {
                this._recursivePostUpdateTransform();
                this.updateTransform();
            }
        }
        //里面计算了_bounds
        this.calculateBounds();
        return rect.copy(this._bounds);
    };
    /**
     * 以自身为世界坐标系的本地包围盒
     * @param {Rectangle} rect - 可选，返回的包围盒数据，不传会用固定临时对象
     * @return {Rectangle} 包围盒
     */
    DisplayObject.prototype.getLocalBounds = function (rect) {
        if (rect === void 0) { rect = DisplayObject.temBounds; }
        var transformRef = this.transform;
        var parentRef = this.parent;
        this.parent = null;
        this.transform = this._tempDisplayObjectParent.transform;
        var bounds = this.getBounds(false, rect);
        this.parent = parentRef;
        this.transform = transformRef;
        //是否考虑算一次回去，因为getBounds里parent为空时会赋值临时父级并执行updateTransform修改了所有子级原来的矩阵
        if (this.parent)
            this.updateTransform();
        return bounds;
    };
    DisplayObject.prototype.calculateBounds = function () {
        //重写
        if (this._lastBoundsID == this._boundsID)
            return;
        this._lastBoundsID = this._boundsID;
    };
    /**
     * 手动调用calculateBounds或getBounds或getLocalBounds时如果发现包围盒计算有误，可以尝试前置调用needUpdateBounds
     */
    DisplayObject.prototype.needUpdateBounds = function () {
        this._lastBoundsID = -1;
    };
    /**
     * 将全局坐标转换到本地坐标值
     * @method globalToLocal
     * @since 1.0.0
     * @public
     * @param {*} point 需要转换的点，存在x和y字段的对象都行
     * @param {Point} bp 最终存入数据的Point对象，不传会使用默认的DisplayObject._bp，多次调用注意该对象覆盖问题
     * @return {Point}
     */
    DisplayObject.prototype.globalToLocal = function (point, bp) {
        if (bp === void 0) { bp = null; }
        return this.worldMatrix.transformPointInverse(point.x, point.y, bp || DisplayObject._bp);
    };
    /**
     * 将本地坐标转换到全局坐标值（stage存在时返回stage上的坐标，不存在为画布全局坐标）
     * @method localToGlobal
     * @public
     * @since 1.0.0
     * @param {*} point 需要转换的点，存在x和y字段的对象都行
     * @param {Point} bp 最终存入数据的Point对象，不传会使用默认的DisplayObject._bp，多次调用注意该对象覆盖问题
     * @return {Point}
     */
    DisplayObject.prototype.localToGlobal = function (point, bp) {
        if (bp === void 0) { bp = null; }
        var wp = this.worldMatrix.transformPoint(point.x, point.y, bp || DisplayObject._bp);
        if (this.stage) {
            //舞台存在时返回舞台上的坐标
            return this.stage.globalToLocal(wp, bp || DisplayObject._bp);
        }
        else {
            //否则返回画布上的坐标
            return wp;
        }
        // return this.worldMatrix.transformPoint(point.x, point.y, bp || DisplayObject._bp);
    };
    /**
     * 调用些方法会冒泡的将事件向显示列表下方传递，主要用于移除舞台，和添加进舞台事件，修改stage
     * @method _onDispatchBubbledEvent
     * @public
     * @since 1.0.0
     * @param {string} type
     * @return {void}
     */
    DisplayObject.prototype._onDispatchBubbledEvent = function (type) {
        var s = this;
        if (type == Event.REMOVED_FROM_STAGE && !s.stage)
            return;
        if (type == Event.REMOVED_FROM_STAGE) {
            s.dispatchEvent(type);
            //以防REMOVED_FROM_STAGE事件里用到了stage
            s.stage = null;
        }
        else if (type == Event.ADDED_TO_STAGE) {
            s.stage = s.parent.stage;
            s.dispatchEvent(type);
        }
    };
    /**
     * webgl渲染
     * @param {WebGLRenderer} renderer - 渲染器
     */
    DisplayObject.prototype.renderWebGL = function (renderer) {
        //子类重写
    };
    /**
     * canvas渲染
     * @param {CanvasRenderer} renderer - 渲染器
     */
    DisplayObject.prototype.renderCanvas = function (renderer) {
        //子类重写
    };
    /**
     * 根据常规属性，设置矩阵属性，挺少用，自己赋值也完全一样，可用于初始化所有数据，考虑废弃
     * @param {number} [x=0] - 位置x
     * @param {number} [y=0] - 位置y
     * @param {number} [scaleX=1] - 缩放x
     * @param {number} [scaleY=1] - 缩放y
     * @param {number} [rotation=0] - 旋转(角度制)
     * @param {number} [skewX=0] - 斜切x（弧度制）
     * @param {number} [skewY=0] - 斜切y（弧度制）
     * @param {number} [anchorX=0] - 锚点x
     * @param {number} [anchorY=0] - 锚点y
     * @return {DisplayObject} 返回自身
     */
    DisplayObject.prototype.setTransform = function (x, y, scaleX, scaleY, rotation, skewX, skewY, anchorX, anchorY) {
        if (x === void 0) { x = 0; }
        if (y === void 0) { y = 0; }
        if (scaleX === void 0) { scaleX = 1; }
        if (scaleY === void 0) { scaleY = 1; }
        if (rotation === void 0) { rotation = 0; }
        if (skewX === void 0) { skewX = 0; }
        if (skewY === void 0) { skewY = 0; }
        if (anchorX === void 0) { anchorX = 0; }
        if (anchorY === void 0) { anchorY = 0; }
        this.position.x = x;
        this.position.y = y;
        this.scale.x = !scaleX ? 1 : scaleX;
        this.scale.y = !scaleY ? 1 : scaleY;
        this.rotation = rotation;
        this.skew.x = skewX;
        this.skew.y = skewY;
        this.anchor.x = anchorX;
        this.anchor.y = anchorY;
        return this;
    };
    /**
     * 基本销毁方法
     */
    DisplayObject.prototype.destroy = function () {
        // super.destroy();//不适用继承的，里面的eventTypes置空很麻烦
        //如果有父级，从中移除自己
        if (this.parent) {
            this.parent.removeChild(this);
        }
        //移除所有监听，放在父级移除自己后面，因为有舞台移除事件
        this.removeAllEventListener();
        //矩阵销毁
        this.transform.destroy();
        //对应属性都置null
        this.transform = null;
        this._localBoundsSelf = null;
        this._bounds = null;
        this.tempDisplayObjectParent = null;
        this._mask = null;
        this.filterArea = null;
        this._filters = null;
        this._enabledFilters = null;
        this.mouseEnable = false;
        //标记为已销毁
        this.destroyed = true;
    };
    Object.defineProperty(DisplayObject.prototype, "alpha", {
        /**
         * 获取透明度，0到1
         */
        get: function () {
            return this._alpha;
        },
        /**
         * 设置透明度，0到1
         */
        set: function (value) {
            if (this._alpha != value) {
                this._alpha = value;
                //是否有必要设置_worldAlpha是否需要更新，一个乘法基本不耗性能
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(DisplayObject.prototype, "x", {
        /**
         * 获取位置x
         */
        get: function () {
            return this.position.x;
        },
        /**
         * 设置位置x
         */
        set: function (value) {
            this.transform.position.x = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(DisplayObject.prototype, "y", {
        /**
         * 获取位置y
         */
        get: function () {
            return this.position.y;
        },
        /**
         * 设置位置y
         */
        set: function (value) {
            this.transform.position.y = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(DisplayObject.prototype, "worldMatrix", {
        /**
         * 获取世界矩阵
         * 手动修改时，this.transform._worldID++,保证子级的worldMatrix会修改，尽量别那么做
         * @member {Matrix}
         * @readonly
         */
        get: function () {
            return this.transform.worldMatrix;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(DisplayObject.prototype, "localMatrix", {
        /**
         * 获取本地矩阵
         * 手动修改时this.transform._parentID=-1;保证其worldMatrix会更新
         * @member {Matrix}
         * @readonly
         */
        get: function () {
            return this.transform.localMatrix;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(DisplayObject.prototype, "position", {
        /**
         * 获取位置对象
         * @member {Point|ObservablePoint}
         */
        get: function () {
            return this.transform.position;
        },
        /**
         * 设置位置对象
         * 传值用于copy，并非赋值，要求传值存在x和y字段
         */
        set: function (value) {
            this.transform.position.copy(value);
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(DisplayObject.prototype, "scale", {
        /**
         * 获取缩放对象
         * @member {Point|ObservablePoint}
         */
        get: function () {
            return this.transform.scale;
        },
        /**
         * 设置缩放对象
         * 传值用于copy，并非赋值，要求传值存在x和y字段
         */
        set: function (value) {
            this.transform.scale.copy(value);
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(DisplayObject.prototype, "scaleX", {
        /**
         * 获取缩放x
         */
        get: function () {
            return this.transform.scale.x;
        },
        /**
         * 设置缩放x
         */
        set: function (value) {
            this.transform.scale.x = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(DisplayObject.prototype, "scaleY", {
        /**
         * 获取缩放y
         */
        get: function () {
            return this.transform.scale.y;
        },
        /**
         * 设置缩放y
         */
        set: function (value) {
            this.transform.scale.y = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(DisplayObject.prototype, "anchor", {
        /**
         * 获取锚点对象
         * @member {Point|ObservablePoint}
         */
        get: function () {
            return this.transform.anchor;
        },
        /**
         * 设置锚点对象
         * 传值用于copy，并非赋值，要求传值存在x和y字段
         */
        set: function (value) {
            this.transform.anchor.copy(value);
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(DisplayObject.prototype, "anchorX", {
        /**
         * 获取锚点x
         */
        get: function () {
            return this.transform.anchor.x;
        },
        /**
         * 设置锚点x
         */
        set: function (value) {
            this.transform.anchor.x = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(DisplayObject.prototype, "anchorY", {
        /**
         * 获取锚点y
         */
        get: function () {
            return this.transform.anchor.y;
        },
        /**
         * 设置锚点y
         */
        set: function (value) {
            this.transform.anchor.y = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(DisplayObject.prototype, "skew", {
        /**
         * 获取斜切对象
         * @member {ObservablePoint}
         */
        get: function () {
            return this.transform.skew;
        },
        /**
         * 设置斜切对象
         * 传值用于copy，并非赋值，要求传值存在x和y字段
         */
        set: function (value) {
            this.transform.skew.copy(value);
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(DisplayObject.prototype, "skewX", {
        /**
         * 获取斜切x，角度制
         */
        get: function () {
            return this.transform.skew.x * RAD_TO_DEG;
        },
        /**
         * 设置斜切x，角度制
         */
        set: function (value) {
            this.transform.skew.x = value * DEG_TO_RAD;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(DisplayObject.prototype, "skewY", {
        /**
         * 获取斜切y，角度制
         */
        get: function () {
            return this.transform.skew.y * RAD_TO_DEG;
        },
        /**
         * 设置斜切y，角度制
         */
        set: function (value) {
            this.transform.skew.y = value * DEG_TO_RAD;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(DisplayObject.prototype, "rotation", {
        /**
         * 获取旋转值,顺时针,角度制
         * @member {number}
         */
        get: function () {
            return this.transform.rotation * RAD_TO_DEG;
        },
        /**
         * 设置旋转，角度制
         */
        set: function (value) {
            this.transform.rotation = value * DEG_TO_RAD;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(DisplayObject.prototype, "worldVisible", {
        /**
         * 自身是否可见,检测所有父级的visible
         * @member {boolean}
         * @readonly
         */
        get: function () {
            var item = this;
            do {
                if (!item.visible) {
                    return false;
                }
                //@ts-ignore
                item = item.parent;
            } while (item);
            return true;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(DisplayObject.prototype, "mask", {
        /**
         * 获取遮罩
         * @member {Graphics}
         */
        get: function () {
            return this._mask;
        },
        set: function (value) {
            //同一个return
            if (this._mask == value)
                return;
            if (this._mask) {
                //原先有的遮罩,重置属性
                this._mask.renderable = true;
                this._mask._isUsedToMask = false;
                // if (this._mask.parent) {
                //     this._mask.parent.removeChild(this._mask)
                //     //是否销毁
                // }
            }
            this._mask = value;
            if (this._mask) {
                this._mask.renderable = false;
                this._mask._isUsedToMask = true;
                //保证更新包围盒
                this._boundsID++;
                //手动添加吧
                // this.parent.addChild(this._mask)
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(DisplayObject.prototype, "width", {
        /**
         * 子类必重写，
         */
        get: function () {
            return this._width;
        },
        /**
         * 子类必重写，如果设置过宽高_width有值且不为0，子类在更新texture时需设置scale
         */
        set: function (value) {
            this._width = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(DisplayObject.prototype, "height", {
        get: function () {
            return this._height;
        },
        set: function (value) {
            this._height = value;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 更新方法，帧循环的监听事件是放在这派发的
     */
    DisplayObject.prototype.update = function () {
        //监听的
        if (this.hasEventListener(Event.ENTER_FRAME)) {
            this.dispatchEvent(Event.ENTER_FRAME);
        }
    };
    //为了hitTestPoint，localToGlobal，globalToLocal等方法不复新不重复生成新的点对象而节约内存
    DisplayObject._bp = new Point();
    DisplayObject._p1 = new Point();
    DisplayObject._p2 = new Point();
    DisplayObject._p3 = new Point();
    DisplayObject._p4 = new Point();
    //bounds缓存
    DisplayObject.temBounds = new Rectangle();
    return DisplayObject;
}(EventDispatcher));
/**
 * 比用call性能好
 * 不会被子类覆盖，部分地方使用
 */
DisplayObject.prototype.displayObjectUpdateTransform = DisplayObject.prototype.updateTransform;
DisplayObject.prototype.displayObjectHitTestPoint = DisplayObject.prototype.hitTestPoint;

/**
 * 容器类
 * @class
 * @extends DisplayObject
 */
var Container = /** @class */ (function (_super) {
    __extends(Container, _super);
    function Container() {
        var _this = _super.call(this) || this;
        /**
         * 为false鼠标事件不再向下传递
         */
        _this.mouseChildren = true;
        _this._instanceType = "Container";
        _this.children = [];
        return _this;
    }
    // /**
    //  * children改变时触发，暂时没地方用到，考虑废弃
    //  * @param {number} index
    //  */
    // onChildrenChange(index: number) {
    //     //子类需要时重写
    // }
    /**
     * 添加child，在所有子级的最上层
     * @param {DisplayObject} child
     * @return {DisplayObject}
     */
    Container.prototype.addChild = function (child) {
        //默认添加在最顶层
        this.addChildAt(child, this.children.length);
        return child;
    };
    /**
     * 批量添加child
     * @param children
     */
    Container.prototype.addChildren = function () {
        var _this = this;
        var children = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            children[_i] = arguments[_i];
        }
        children.forEach(function (child) { _this.addChild(child); });
        return children;
    };
    /**
     * 在相应index处添加child
     * @param {DisplayObject} child - 被添加的子级
     * @param {number} index - 需要放置的索引位置，指已存在子级的索引，一般用于往子级之间插入
     * @return {DisplayObject} 返回自身
     */
    Container.prototype.addChildAt = function (child, index) {
        if (!child)
            return;
        var s = this;
        var sameParent = (s == child.parent);
        var len;
        if (child.parent) {
            if (!sameParent) {
                child.parent.removeChild(child);
            }
            else {
                len = s.children.length;
                for (var i = 0; i < len; i++) {
                    if (s.children[i] == child) {
                        s.children.splice(i, 1);
                        break;
                    }
                }
            }
        }
        child.parent = s;
        //保证child的transform会被更新
        child.transform._parentID = -1;
        //确保包围盒重新计算
        this._boundsID++;
        len = s.children.length;
        if (index >= len) {
            s.children[s.children.length] = child;
            index = len;
        }
        else if (index == 0 || index < 0) {
            s.children.unshift(child);
            index = 0;
        }
        else {
            s.children.splice(index, 0, child);
        }
        if (s.stage && !sameParent) {
            // child["_cp"] = true;
            child._onDispatchBubbledEvent(Event.ADDED_TO_STAGE);
        }
        // this.onChildrenChange(index);
        return child;
    };
    /**
     * 只用于交换索引
     * @param {DisplayObject} child
     * @param {DisplayObject} child2
     */
    Container.prototype.swapChildren = function (child1, child2) {
        if (child1 === child2) {
            return;
        }
        var s = this;
        var id1 = -1;
        var id2 = -1;
        var childCount = s.children.length;
        if (typeof (child1) == "number") {
            id1 = child1;
        }
        else {
            id1 = s.getChildIndex(child1);
        }
        if (typeof (child2) == "number") {
            id2 = child2;
        }
        else {
            id2 = s.getChildIndex(child2);
        }
        if (id1 == id2 || id1 < 0 || id1 >= childCount || id2 < 0 || id2 >= childCount) {
            return false;
        }
        else {
            var temp = s.children[id1];
            s.children[id1] = s.children[id2];
            s.children[id2] = temp;
            // this.onChildrenChange(id1 < id2 ? id1 : id2);
            return true;
        }
    };
    /**
     * 获取child的层级索引index
     * @param {DisplayObject} child - 需要获取索引的子级
     * @return {number} children内的索引
     */
    Container.prototype.getChildIndex = function (child) {
        var index = this.children.indexOf(child);
        if (index === -1) {
            return null;
        }
        return index;
    };
    /**
     * 设置child的层级索引
     * @param {DisplayObject} child
     * @param {number} index
     */
    Container.prototype.setChildIndex = function (child, index) {
        this.addChildAt(child, index);
    };
    /**
     * 根据索引获取子级对象
     * @param {number} index
     * @return {DisplayObject}
     */
    Container.prototype.getChildAt = function (index) {
        if (index < 0 || index >= this.children.length) {
            return null;
        }
        return this.children[index];
    };
    /**
     * 通过名字获取一个子级，找到一个符合的就返回
     * @param name 名字或正则
     * @param isRecursive 是否递归往子级查找，默认false
     */
    Container.prototype.getChildByName = function (name, isRecursive) {
        if (isRecursive === void 0) { isRecursive = false; }
        if (!name)
            return null;
        var s = this;
        var rex;
        if (typeof (name) == "string") {
            rex = new RegExp("^" + name + "$");
        }
        else {
            rex = name;
        }
        var elements = [];
        Container._getElementsByName(rex, s, true, isRecursive, elements);
        return elements[0] || null;
    };
    /**
     * 通过名字获取子级数组
     * @param name 名字或正则
     * @param isRecursive 是否递归往子级查找，默认false
     */
    Container.prototype.getChildrenByName = function (name, isRecursive) {
        if (isRecursive === void 0) { isRecursive = false; }
        if (!name)
            return null;
        var s = this;
        var rex;
        if (typeof (name) == "string") {
            rex = new RegExp("^" + name + "$");
        }
        else {
            rex = name;
        }
        var elements = [];
        Container._getElementsByName(rex, s, false, isRecursive, elements);
        return elements;
    };
    /**
     * 移除child
     * @param {DisplayObject} child
     * @return {DisplayObject}
     */
    Container.prototype.removeChild = function (child) {
        var index = this.children.indexOf(child);
        if (index === -1)
            return null;
        this.removeChildAt(index);
        return child;
    };
    /**
     * 在index索引处移除子级对象
     * @param {number} index
     * @return {DisplayObject} 移除的子级对象
     */
    Container.prototype.removeChildAt = function (index) {
        var s = this;
        var child;
        var len = s.children.length - 1;
        if (len < 0)
            return;
        if (index == len) {
            child = s.children.pop();
        }
        else if (index == 0) {
            child = s.children.shift();
        }
        else {
            child = s.children.splice(index, 1)[0];
        }
        child._onDispatchBubbledEvent(Event.REMOVED_FROM_STAGE);
        //保证子级会被更新
        child.parent = null;
        child.transform._parentID = -1;
        //保证包围盒重新计算
        this._boundsID++;
        // this.onChildrenChange(index);
        return child;
    };
    /**
     * 批量移除child，
     * @param children 不传参数，表示全部移除
     */
    Container.prototype.removeChildren = function () {
        var _this = this;
        var children = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            children[_i] = arguments[_i];
        }
        //待测试，arr.splice(0)会全部删除，arr.splice(0,undefined)不会，所以this.spliceChildren(0)下面执行的是splice(0,undefined)
        if (!children.length)
            return this.spliceChildren(0, this.children.length);
        children.forEach(function (child) { _this.removeChild(child); });
        return children;
    };
    /**
     * 移除所有子级
     * @returns 返回移除的子级的数组
     */
    Container.prototype.removeAllChildren = function () {
        return this.removeChildren();
    };
    /**
     * 通过索引批量移除child
     * @param {number} [beginIndex=0] 开始索引，包括自己
     * @param {number} [endIndex=this.children.length] 结束索引，不包括自己
     * @returns {DisplayObject[]} 移除的所有子级数组
     */
    Container.prototype.removeChildrenAt = function (beginIndex, endIndex) {
        if (beginIndex === void 0) { beginIndex = 0; }
        if (endIndex === void 0) { endIndex = this.children.length; }
        var begin = beginIndex;
        var end = typeof endIndex === 'number' ? endIndex : this.children.length;
        var range = end - begin;
        if (range > 0 && range <= end) {
            return this.spliceChildren(begin, range);
        }
        else if (range === 0 && this.children.length === 0) {
            return [];
        }
        throw new RangeError('removeChildren: 移除范围有误');
    };
    /**
     * 类比数组的splice方法，但是没有第三个参数，不能添加
     * @param beginIndex 开始索引
     * @param count 移除数量
     */
    Container.prototype.spliceChildren = function (beginIndex, count) {
        var removed = this.children.splice(beginIndex, count);
        if (!removed.length)
            return [];
        for (var i = 0; i < removed.length; ++i) {
            removed[i].parent = null;
            if (removed[i].transform) {
                removed[i].transform._parentID = -1;
            }
        }
        this._boundsID++;
        // this.onChildrenChange(beginIndex);
        for (var i = 0; i < removed.length; ++i) {
            removed[i]._onDispatchBubbledEvent(Event.REMOVED_FROM_STAGE);
        }
        return removed;
    };
    /**
     * 更新矩阵
     */
    Container.prototype.updateTransform = function () {
        //自己先算
        _super.prototype.updateTransform.call(this);
        //考虑是否要加，
        //this._boundsID++;
        //children遍历计算
        for (var i = 0, j = this.children.length; i < j; ++i) {
            var child = this.children[i];
            if (child.visible) { //为了优化性能，但是会出现，不显示的对象，获取到的位置等信息是错误的，但是可以自行调用updateTransform
                child.updateTransform();
            }
        }
    };
    /**
     * 父类重写
     * 都是全局的
     */
    Container.prototype.calculateBounds = function () {
        if (this._lastBoundsID == this._boundsID)
            return;
        this._lastBoundsID = this._boundsID;
        this._bounds.clear();
        //算自己的
        this._calculateBounds();
        for (var i = 0; i < this.children.length; i++) {
            var child = this.children[i];
            if (!child.visible || !child.renderable) {
                continue;
            }
            child.calculateBounds();
            if (child.mask) {
                child.mask.calculateBounds();
                //取交集矩形
                if (child._bounds.x < child.mask._bounds.x) {
                    child._bounds.x = child.mask._bounds.x;
                }
                if (child._bounds.y < child.mask._bounds.y) {
                    child._bounds.y = child.mask._bounds.y;
                }
                if (child._bounds.width > child.mask._bounds.width) {
                    child._bounds.width = child.mask._bounds.width;
                }
                if (child._bounds.height > child.mask._bounds.height) {
                    child._bounds.height = child.mask._bounds.height;
                }
                Rectangle.createFromRects(this._bounds, child._bounds);
            }
            //到时处理filterArea
            else if (child.filterArea) ;
            else {
                Rectangle.createFromRects(this._bounds, child._bounds);
            }
        }
    };
    /**
     * 加"_"的方法基本是为了自己特殊处理
     */
    Container.prototype._calculateBounds = function () {
        //子类自己重写
    };
    /**
     * 检测点是否在任何child上
     * 重写父类方法
     */
    Container.prototype.hitTestPoint = function (globalPoint, isMouseEvent) {
        if (isMouseEvent === void 0) { isMouseEvent = false; }
        if (!this.visible)
            return null;
        //如果禁止子级的鼠标事件
        if (isMouseEvent && !this.mouseChildren)
            return null;
        var children = this.children;
        var length = children.length;
        var child, hitDisplayObject;
        //后序遍历，后添加的在上层
        for (var i = length - 1; i >= 0; i--) {
            child = children[i];
            //当作遮罩的不作为检测，跳过
            if (child._isUsedToMask)
                continue;
            //有遮罩，但是不在遮罩内，跳过
            if (child.mask && !child.mask.hitTestPoint(globalPoint, isMouseEvent))
                continue;
            //检测
            hitDisplayObject = child.hitTestPoint(globalPoint, isMouseEvent);
            //存在直接返回
            if (hitDisplayObject)
                return hitDisplayObject;
        }
        return null;
    };
    /**
     * webgl渲染
     * @param {WebglRenderer} renderer - 渲染器
     */
    Container.prototype.renderWebGL = function (renderer) {
        //不可见，全局透明度为0，或者 不渲染，直接return
        if (!this.visible || this._worldAlpha <= 0 || !this.renderable) {
            return;
        }
        //如果有遮罩，但是遮罩无数据，直接return
        if (this.mask) {
            // //Shape遮罩，或者Sprite遮罩
            // if (this.mask.texture) {
            //     this.mask.updateShape && this.mask.updateShape();//更新一下
            //     if (!this.mask.texture.valid) return;
            // }
            // //Graphics遮罩，其实这个判断也包括了Sprite的纹理为空的情况
            // else if (!this.mask.graphicsData || !this.mask.graphicsData.length) {
            //     return;
            // }
            if (!judgeMaskEnable(this.mask))
                return;
        }
        //是否有遮罩。到时如果有滤镜，
        if (this.mask || (this.filters && this.filters.length)) {
            this.renderAdvancedWebGL(renderer);
        }
        else {
            //自身先渲染
            this._renderWebGL(renderer);
            //遍历children
            for (var i = 0, j = this.children.length; i < j; ++i) {
                this.children[i].renderWebGL(renderer);
            }
        }
    };
    /**
     * 高级渲染方法
     *
     * @private
     * @param {WebGLRenderer} renderer - 渲染器
     */
    Container.prototype.renderAdvancedWebGL = function (renderer) {
        //之前的批处理刷掉先
        renderer.batchManager.flush();
        //有滤镜再说
        var filters = this.filters;
        // push filter first as we need to ensure the stencil buffer is correct for any masking
        if (filters) {
            if (!this._enabledFilters)
                this._enabledFilters = [];
            //重置
            this._enabledFilters.length = 0;
            //筛选可用的
            for (var i = 0; i < filters.length; i++) {
                if (filters[i].enabled)
                    this._enabledFilters.push(filters[i]);
            }
            if (this._enabledFilters.length)
                renderer.filterManager.pushFilter(this, this._enabledFilters);
        }
        var mask = this.mask;
        if (mask) {
            //先画遮罩
            renderer.maskManager.pushMask(this, this.mask);
        }
        //渲染自身
        this._renderWebGL(renderer);
        //遍历children
        for (var i = 0, j = this.children.length; i < j; i++) {
            this.children[i].renderWebGL(renderer);
        }
        //刷掉批处理
        renderer.batchManager.flush();
        if (mask) {
            //移除遮罩，支持多重遮罩
            renderer.maskManager.popMask(this, this.mask);
        }
        //移除滤镜
        if (filters && this._enabledFilters && this._enabledFilters.length)
            renderer.filterManager.popFilter();
    };
    /**
     * 自身webgl渲染方式
     * @private
     * @param {WebglRenderer} renderer - 渲染器
     */
    Container.prototype._renderWebGL = function (renderer) {
        //自身绘制方法
    };
    /**
     * canvas渲染方式
     * @param {CanvasRenderer} renderer - 渲染器
     */
    Container.prototype.renderCanvas = function (renderer) {
        if (!this.visible || this._worldAlpha <= 0 || !this.renderable) {
            return;
        }
        if (this.mask) {
            //遮罩不可用无数据，return
            if (!judgeMaskEnable(this.mask))
                return;
            renderer.maskManager.pushMask(this.mask);
        }
        this._renderCanvas(renderer);
        for (var i = 0, j = this.children.length; i < j; ++i) {
            this.children[i].renderCanvas(renderer);
        }
        if (this.mask) {
            renderer.maskManager.popMask(renderer);
        }
    };
    /**
     * 自身canvas渲染方法
     * @private
     * @param {CanvasRenderer} renderer - The renderer
     */
    Container.prototype._renderCanvas = function (renderer) {
        //自身绘制方法
    };
    /**
     * 节点每帧更新方法，注意别覆盖，否则每帧监听将失效，子类可继承修改
     */
    Container.prototype.update = function () {
        // if (!this.visible) return;//从root往下时block（比如下面子级的visible判断），自身不进行判断
        //更新自己的
        _super.prototype.update.call(this);
        //更新儿子们的
        var len = this.children.length;
        for (var i = len - 1; i >= 0; i--) {
            var child = this.children[i];
            if (child.visible)
                child.update();
        }
    };
    /**
     * 调用此方法对自己及其child触发一次指定事件
     * @method _onDispatchBubbledEvent
     * @public
     * @param {string} type
     * @since 1.0.0
     */
    Container.prototype._onDispatchBubbledEvent = function (type) {
        var s = this;
        var len = s.children.length;
        if (type == Event.REMOVED_FROM_STAGE && !s.stage)
            return;
        _super.prototype._onDispatchBubbledEvent.call(this, type);
        for (var i = 0; i < len; i++) {
            s.children[i]._onDispatchBubbledEvent(type);
        }
    };
    /**
     * 销毁方法，也会销毁子级
     */
    Container.prototype.destroy = function () {
        var s = this;
        //让子级也destroy
        for (var i = s.children.length - 1; i >= 0; i--) {
            s.children[i].destroy();
        }
        _super.prototype.destroy.call(this);
        this.mouseChildren = false;
    };
    Object.defineProperty(Container.prototype, "width", {
        /**
         * 一般用于获取宽高并设置，会修改缩放
         * 包括子级的,容器Container的尽量少用，子类可重写
         * @member {number}
         */
        get: function () {
            return this.scale.x * this.getLocalBounds().width;
        },
        set: function (value) {
            var width = this.getLocalBounds().width;
            if (width !== 0) {
                this.scale.x = value / width;
            }
            else {
                this.scale.x = 1;
            }
            //子类有用，有_width,才需设置scaleX
            this._width = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Container.prototype, "height", {
        /**
         * 高度同width
         * @member {number}
         */
        get: function () {
            return this.scale.y * this.getLocalBounds().height;
        },
        set: function (value) {
            var height = this.getLocalBounds().height;
            if (height !== 0) {
                this.scale.y = value / height;
            }
            else {
                this.scale.y = 1;
            }
            this._height = value;
        },
        enumerable: false,
        configurable: true
    });
    //全局遍历
    /**
     * @method _getElementsByName
     * @param {RegExp} rex
     * @param {Container} root
     * @param {boolean} isOnlyOne
     * @param {boolean} isRecursive
     * @param {Array<DisplayObject>} resultList
     * @private
     * @static
     */
    Container._getElementsByName = function (rex, root, isOnlyOne, isRecursive, resultList) {
        var len = root.children.length;
        if (len > 0) {
            var name = void 0;
            var child = void 0;
            for (var i = 0; i < len; i++) {
                child = root.children[i];
                name = child.name;
                if (name && name != "") {
                    if (rex.test(name)) {
                        resultList[resultList.length] = child;
                        if (isOnlyOne) {
                            return;
                        }
                    }
                }
                if (isRecursive) {
                    if (child["children"] != null) {
                        Container._getElementsByName(rex, child, isOnlyOne, isRecursive, resultList);
                    }
                }
            }
        }
    };
    /**
     * 操作子级的所有方法，需要维护
     */
    Container._childrenOperationMethods = [
        //添加子级的方法
        "addChild", "addChildAt", "addChildren",
        //移除子级的方法
        "removeChild", "removeChildAt", "removeChildren", "removeAllChildren", "removeChildrenAt", "spliceChildren",
        //获取子级的方法
        "getChildAt", "getChildByName", "getChildrenByName",
        //获取子级索引的方法
        "getChildIndex",
        //改变子级索引的方法
        "setChildIndex", "swapChildren"
    ];
    return Container;
}(DisplayObject));
Container.prototype.containerUpdateTransform = Container.prototype.updateTransform;
function judgeMaskEnable(mask) {
    if (!mask)
        return false;
    //Shape遮罩，或者Sprite遮罩
    if (mask.texture) {
        mask.updateShape && mask.updateShape(); //更新一下
        if (!mask.texture.valid)
            return false;
    }
    //Graphics遮罩，其实这个判断也包括了Sprite的纹理为空的情况
    else if (!mask.graphicsData || !mask.graphicsData.length) {
        return false;
    }
    return true;
}

// import { devicePixelRatio } from "../const";
/**
 * canvas上的html标签浮层
 * 不能用于容器
 * 注意canvas所在标签和自身htmlElement样式position设置为absolute
 * @class FloatDisplay
 * @extends DisplayObject
 * @public
 * @since 1.0.0
 */
var FloatDisplay = /** @class */ (function (_super) {
    __extends(FloatDisplay, _super);
    /**
     * 构造函数
     * @method FloatDisplay
     * @since 1.0.0
     * @public
     * @example
     *  //创建悬浮的html元素
     *  var section = document.createElement('section');
     *   section.id = "rule";
     *   section.style.overflowX = "hidden";
     *   section.style.overflowY = "auto";
     *   section.style.width = w + "px";
     *   section.style.height = h + "px";
     *   section.style.lineHeight = lh + "px";
     *   section.style.fontFamily = '微软雅黑';
     *   section.style.fontSize = fs + 'px';
     *   section.style.color = "#ffffff";
     *   section.style.position = "absolute";
     *   //创建Floatview 把我们要悬浮的元素封装进去
     *   var rule = new FloatDisplay();
     *   stage.addChild(rule);
     *   rule.x = ox;
     *   rule.y = oy;
     *   rule.init(section);
     *   section.innerHTML = DataManager.ins.getData("ajaxElement").data.rule;
     *
     */
    function FloatDisplay() {
        var _this = _super.call(this) || this;
        /**
         * 包装的html元素
         * @property htmlElement
         * @public
         * @since 1.0.0
         * @type{HtmlElement}
         */
        _this.htmlElement = null;
        /**
         * 是否已经添加了舞台事件
         * @property _isAdded
         * @since 1.0.0
         * @type {boolean}
         * @private
         */
        _this._isAdded = false;
        var s = _this;
        s._instanceType = "FloatDisplay";
        s.addEventListener(Event.REMOVED_FROM_STAGE, function (e) {
            if (s.htmlElement) {
                s.htmlElement.style.display = "none";
            }
            //移除updateStyle监听
            s.stage.removeEventListener(Event.ENTER_FRAME, s.updateStyle, s);
        });
        s.addEventListener(Event.ADDED_TO_STAGE, function (e) {
            if (s.htmlElement) {
                var style = s.htmlElement.style;
                if (!s._isAdded) {
                    s._isAdded = true;
                    // if (s.stage["rootDiv"]) {
                    //     s.stage["rootDiv"].insertBefore(s.htmlElement, s.stage["rootDiv"].childNodes[0]);
                    // }
                    // //没有div直接加在body里吧
                    // else {
                    //     document.body.appendChild(s.htmlElement)
                    // }
                    s.addHtmlElement();
                }
                else {
                    if (s.htmlElement && s.visible) {
                        style.display = "block"; //"inline-block"
                    }
                }
            }
            //在stage上监听循环，修改显示
            s.stage.addEventListener(Event.ENTER_FRAME, s.updateStyle, s);
        });
        _this._transformID = -1;
        return _this;
    }
    /**
     * 初始化方法,htmlElement 一定要设置width和height样式,并且一定要用px单位
     * @method init
     * @public
     * @since 1.0.0
     * @param {HtmlElement} htmlElement 需要封装起来的html元素的引用。你可以通过这个引用来调用或设置此元素自身的属性方法和事件,甚至是样式
     */
    FloatDisplay.prototype.init = function (htmlElement) {
        var s = this;
        var she;
        if (typeof (htmlElement) == "string") {
            she = document.getElementById(htmlElement);
        }
        else if (htmlElement._instanceType == "Video") {
            she = htmlElement.media;
        }
        else {
            she = htmlElement;
        }
        //原先有的先移除
        if (s.htmlElement)
            s.removeHtmlElement();
        var style = she.style;
        style.position = "absolute";
        style.display = "none";
        style.transformOrigin = style.WebkitTransformOrigin = "0 0 0";
        var ws = s.getStyle(she, "width");
        var hs = s.getStyle(she, "height");
        var w = 0, h = 0;
        if (ws.indexOf("px")) {
            w = parseInt(ws);
        }
        if (hs.indexOf("px")) {
            h = parseInt(hs);
        }
        // s._bounds.width = w;
        // s._bounds.height = h;
        s._localBoundsSelf.width = w;
        s._localBoundsSelf.height = h;
        s.htmlElement = she;
        //如果原先在舞台上，加入，是否显示下一帧吧
        if (s.stage) {
            s._isAdded = true;
            // if (s.stage["rootDiv"]) {
            //     s.stage["rootDiv"].insertBefore(s.htmlElement, s.stage["rootDiv"].childNodes[0]);
            // }
            // //没有div直接加在body里吧
            // else {
            //     document.body.appendChild(s.htmlElement)
            // }
            s.addHtmlElement();
        }
    };
    /**
     * @method getStyle
     * @param {HTMLElement} elem
     * @param cssName
     * @return {any}
     */
    FloatDisplay.prototype.getStyle = function (elem, cssName) {
        //如果该属性存在于style[]中，则它最近被设置过(且就是当前的)
        if (elem.style[cssName]) {
            return elem.style[cssName];
        }
        if (document.defaultView && document.defaultView.getComputedStyle) {
            //它使用传统的"text-Align"风格的规则书写方式，而不是"textAlign"
            cssName = cssName.replace(/([A-Z])/g, "-$1");
            cssName = cssName.toLowerCase();
            //获取style对象并取得属性的值(如果存在的话)
            var s = document.defaultView.getComputedStyle(elem, "");
            return s && s.getPropertyValue(cssName);
        }
        return null;
    };
    /**
     * 考虑放到stage里，因为父级的visible修改不会调用updateStyle
     * @method updateStyle
     * @public
     * @since 1.1.4
     */
    FloatDisplay.prototype.updateStyle = function () {
        var s = this;
        var o = s.htmlElement;
        if (o) {
            var style = o.style;
            var visible = s.visible;
            //还得考虑是否在stage里
            if (!s.stage) {
                visible = false;
            }
            if (visible) {
                var parent = s.parent;
                while (parent) {
                    if (!parent.visible) {
                        visible = false;
                        break;
                    }
                    parent = parent.parent;
                }
            }
            var show = visible ? "block" : "none";
            if (show != style.display) {
                style.display = show;
            }
            if (visible) {
                if (this._transformID != this.transform._worldID) {
                    this._transformID = this.transform._worldID;
                    var mtx = s.transform.worldMatrix;
                    var d = s.stage["_dpi"] || s.stage["dpi"]; //devicePixelRatio;//不用设备的,改成stage的
                    style.transform = style.webkitTransform = "matrix(" + (mtx.a / d).toFixed(4) + "," + (mtx.b / d).toFixed(4) + "," + (mtx.c / d).toFixed(4) + "," + (mtx.d / d).toFixed(4) + "," + (mtx.tx / d).toFixed(4) + "," + (mtx.ty / d).toFixed(4) + ")";
                }
                style.opacity = s._worldAlpha;
            }
        }
    };
    /**
     * 移除htmlElement
     */
    FloatDisplay.prototype.removeHtmlElement = function () {
        var s = this;
        var elem = s.htmlElement;
        if (elem) {
            elem.style.display = "none";
            if (elem.parentNode) {
                elem.parentNode.removeChild(elem);
            }
            s._isAdded = false;
            s.htmlElement = null;
        }
    };
    //放在stage的帧循环的监听里了
    // public renderCanvas() {
    //     this.updateStyle();
    // }
    // public renderWebGL() {
    //     this.updateStyle();
    // }
    FloatDisplay.prototype.addHtmlElement = function () {
        var _a = this, stage = _a.stage, htmlElement = _a.htmlElement;
        if (!stage || !htmlElement)
            return;
        var divParent = this.stage["canvas"].parentNode;
        if (divParent) {
            divParent.insertBefore(htmlElement, divParent.childNodes[0]);
        }
        else {
            //没有div直接加在body里
            document.body.appendChild(htmlElement);
        }
    };
    FloatDisplay.prototype.destroy = function () {
        _super.prototype.destroy.call(this);
        this.removeHtmlElement();
    };
    return FloatDisplay;
}(DisplayObject));

/**
 * 加载器，不做缓存判断，所有的外部自行缓存，或者判断是否要进加载器
 * 仅仅是加载方法集成
 * 感觉没必要集成EventDispatcher
 * 加载方法都是回调方式
 * 无特殊要求的直接用GlobalLoader
 * 这里所有load方法参数都是（回调函数，路径）
 * 兼容了web和tb环境
 */
var Loader = /** @class */ (function (_super) {
    __extends(Loader, _super);
    /**
     *
     */
    function Loader() {
        var _this = _super.call(this) || this;
        /**
         * 记录原始数据，json和image，贴图在建立时会被缓存
         * 需要缓存的都用在回调里自行缓存，比如弄个RES
         */
        _this.caches = {};
        _this._instanceType = "Loader";
        console.warn("Instance GlobalLoader with class Loader will be abandoned soon, use each load methods instead(such as loadImage) and change parameters");
        return _this;
    }
    /**
     * 加载图集
     * @param callback
     * @param url 图集一般是png格式,传的是json,在callback自行拆分
     */
    Loader.prototype.loadSheet = function (callback, url) {
        var _this = this;
        var pngFile = url.substring(0, url.lastIndexOf('.')) + '.png';
        this.loadImage(function (suc, data) {
            if (suc) {
                _this.cache(pngFile, data);
                if (_this.caches[url]) {
                    callback(true, { json: _this.caches[url], img: data });
                    //已回调,释放置空
                    _this.caches[url] = null;
                    _this.caches[pngFile] = null;
                }
            }
            else {
                callback(false);
            }
        }, pngFile);
        this.loadJson(function (suc, data) {
            if (suc) {
                _this.cache(url, data);
                if (_this.caches[pngFile]) {
                    callback(true, { json: data, img: _this.caches[pngFile] });
                    //已回调,释放置空
                    _this.caches[url] = null;
                    _this.caches[pngFile] = null;
                }
            }
            else {
                callback(false);
            }
        }, url);
    };
    /**
     * 加载json文件
     * @param callback
     * @param url
     */
    Loader.prototype.loadJson = function (callback, url) {
        //@ts-ignore ,正式环境不能使用request，走downloadFile
        // my.request({
        //     url: url,
        //     dataType: "json",
        //     success: (res) => {
        //         callback(true, res.data)
        //     },
        //     fail: function (res) {
        //         // my.alert({
        //         //   title: JSON.stringify(res)
        //         // });
        //         callback(false, res)
        //     }
        // });
        if (getEnv() == "tb") {
            // this.tbLoad(callback, url, "utf8")
            this.tbLoad(function (s, res) {
                callback(s, s ? JSON.parse(res) : res); //utf8返回的数字符串
            }, url, "utf8");
            return;
        }
        //web环境
        this.loadRawWeb(callback, url, "json");
    };
    /**
     * 加载ArrayBuffer
     * @param callback
     * @param url
     */
    Loader.prototype.loadAB = function (callback, url) {
        if (getEnv() == "tb") {
            this.tbLoad(callback, url, "ArrayBuffer");
        }
        else {
            this.loadRawWeb(callback, url, "arraybuffer");
        }
    };
    /**
     * 加载文本
     * @param callback
     * @param url
     */
    Loader.prototype.loadText = function (callback, url) {
        if (getEnv() == "tb") {
            this.tbLoad(callback, url, "utf8");
        }
        else {
            this.loadRawWeb(callback, url, "text");
        }
    };
    /**
     * web环境原生加载方式
     * @param callback
     * @param url
     * @param type
     */
    Loader.prototype.loadRawWeb = function (callback, url, type) {
        if (type === void 0) { type = "json"; }
        //每次都要new
        var _req;
        if (window["XMLHttpRequest"]) {
            _req = new XMLHttpRequest();
        }
        else if (window["ActiveXObject"]) {
            _req = new window["ActiveXObject"]();
        }
        else {
            // alert("请升级至最新版本的浏览器")
            callback(false, "your browser doesnt support XMLHttpRequest!");
            return;
        }
        if (_req != null) {
            _req.open("GET", url, true);
            _req.responseType = type;
            _req.send();
            _req.onreadystatechange = function () {
                // if (_req.readyState == 4 && _req.status == 200) {
                //     callback(true, _req.response)
                // }
                if (_req.readyState == 4) {
                    var status = _req.status;
                    if ((status >= 200 && status < 300) || //2XX表示有效响应
                        status == 304 //304意味着是从缓存读取
                    ) {
                        callback(true, _req.response);
                    }
                    else {
                        callback(false, "request.status:" + status);
                    }
                }
            };
            // _req.onerror = (reason): void => {
            //     callback(false, reason)
            // }
        }
    };
    /**
     * 加载图片
     * @param callback
     * @param url
     */
    Loader.prototype.loadImage = function (callback, url) {
        var img = createImage();
        //之前的劫持下
        // window["Image"] = function () {
        //     var image = canvas.createImage()
        //     return image
        // }
        // let img = new Image()
        img.onload = function () {
            callback(true, img);
        };
        img.onerror = function () {
            callback(false);
        };
        //坑爹中文，decodeURI一次是为了以防链接被encode过一次
        url = encodeURI(decodeURI(url));
        //除了base64的路径，其他都设置了跨域，其实有部分服务器不允许跨域，不能设置anonymous
        if (url.indexOf('data:') !== 0)
            img.crossOrigin = "anonymous";
        img.src = url;
    };
    /**
     * 淘宝加载方式
     * @param callback
     * @param url 云存储链接cloud或者阿里系白名单域名
     */
    Loader.prototype.tbLoad = function (callback, url, type) {
        var _this = this;
        if (type === void 0) { type = "ArrayBuffer"; }
        //类似这种地址"cloud://A8673B47AAA58993A24A6718E203B967//dice.svga"
        if (url.indexOf("cloud://") == 0) {
            this.getTbTempUrl(function (src) {
                _this.downloadReadFile(callback, src, type);
            }, url);
        }
        else {
            this.downloadReadFile(callback, url, type);
        }
    };
    /**
     * 淘宝小程序，获取云存储临时cdn地址
     * @param callback
     * @param url
     */
    Loader.prototype.getTbTempUrl = function (callback, url) {
        //@ts-ignore
        var cloud = getApp().cloud;
        //获取临时地址
        cloud.file.getTempFileURL({ fileId: [url] }).then(function (urls) {
            callback(urls[0].url.replace('-internal', ''));
        }).catch(function (err) {
            console.error(err);
        });
    };
    /**
     *
     * @param callback
     * @param url
     * @param type 指定的字符编码，不传表示以 ArrayBuffer 格式读取文件的二进制内容
     */
    Loader.prototype.downloadReadFile = function (callback, url, type) {
        if (type === void 0) { type = "ArrayBuffer"; }
        //@ts-ignore
        var tbMy = my;
        tbMy.downloadFile({
            url: url,
            success: function (res) {
                var i = res.apFilePath; //临时地址是否有必要缓存下，如果读不到再考虑下载。
                tbMy.getFileSystemManager().readFile({
                    filePath: i,
                    encoding: type === "ArrayBuffer" ? "" : type,
                    success: function (r) {
                        callback(true, r.data); //注意是r.data
                        // actions.load_viaProto(r.data, cb, failure);
                    },
                    fail: function (res) {
                        callback(false, res);
                    }
                });
            },
            fail: function (res) {
                callback(false, res);
            },
        });
    };
    Loader.prototype.cache = function (name, data) {
        if (this.caches[name]) {
            console.log("rewrite orign data:" + name);
        }
        this.caches[name] = data;
    };
    return Loader;
}(EventDispatcher));
/**
 * 一个全局加载器实例
 */
var GlobalLoader = new Loader();
//https://yun.duiba.com.cn/db_games/activity/yilian0726/1565580040/resource/result/resultAlta1.json
//"https://yun.duiba.com.cn/db_games/activity/etc/optionImages/%E5%8D%8E%E4%B8%BAP30.jpg"

/**
 * 加载图片
 * @param url 图片路径
 * @param onSuccess
 * @param onFail
 * @param crossOrigin 默认anonymous
 */
function loadImage(url, onSuccess, onFail, crossOrigin) {
    if (crossOrigin === void 0) { crossOrigin = "anonymous"; }
    var img = createImage();
    img.onload = function () {
        onSuccess(img);
    };
    img.onerror = function () {
        onFail && onFail();
    };
    //坑爹中文，decodeURI一次是为了以防链接被encode过一次
    url = encodeURI(decodeURI(url));
    //除了base64的路径，其他都设置了跨域，其实有部分服务器不允许跨域，不能设置anonymous
    if (url.indexOf('data:') !== 0)
        img.crossOrigin = crossOrigin;
    img.src = url;
}
/**
 * 加载json
 * @param {string} url
 * @param onSuccess
 * @param onFail
 */
function loadJson(url, onSuccess, onFail) {
    loadRaw(url, onSuccess, onFail, ResponseDataType.json);
}
/**
 * 加载二进制数据
 * @param {string} url
 * @param onSuccess
 * @param onFail
 */
function loadArrayBuffer(url, onSuccess, onFail) {
    loadRaw(url, onSuccess, onFail, ResponseDataType.arraybuffer);
}
/**
 * 加载文本
 * @param {string} url
 * @param onSuccess
 * @param onFail
 */
function loadText(url, onSuccess, onFail) {
    loadRaw(url, onSuccess, onFail, ResponseDataType.text);
}
/**
 * 加载原始数据，需要传type，否则按照文本加载
 * @param url
 * @param onSuccess
 * @param onFail
 * @param type 返回数据类型，默认text
 */
function loadRaw(url, onSuccess, onFail, type) {
    if (type === void 0) { type = ResponseDataType.text; }
    (getEnv() == "tb" ? tbLoad : loadRawWeb)(url, onSuccess, onFail, type);
}
/**
 * 返回数据类型
 */
var ResponseDataType;
(function (ResponseDataType) {
    ResponseDataType["text"] = "text";
    ResponseDataType["json"] = "json";
    ResponseDataType["arraybuffer"] = "arraybuffer";
})(ResponseDataType || (ResponseDataType = {}));
/**
 * web环境原生加载方式
 * @param callback
 * @param url
 * @param type
 */
function loadRawWeb(url, onSuccess, onFail, type) {
    if (type === void 0) { type = ResponseDataType.text; }
    //每次都要new
    var _req;
    if (window["XMLHttpRequest"]) {
        _req = new XMLHttpRequest();
    }
    else if (window["ActiveXObject"]) {
        _req = new window["ActiveXObject"]();
    }
    else {
        onFail && onFail("your browser doesnt support XMLHttpRequest!");
        return;
    }
    if (_req != null) {
        _req.open("GET", url, true);
        _req.responseType = type;
        _req.send();
        _req.onreadystatechange = function () {
            // if (_req.readyState == 4 && _req.status == 200) {
            //     callback(true, _req.response)
            // }
            if (_req.readyState == 4) {
                var status = _req.status;
                if ((status >= 200 && status < 300) || //2XX表示有效响应
                    status == 304 //304意味着是从缓存读取
                ) {
                    onSuccess(_req.response);
                }
                else {
                    onFail && onFail("request.status:" + status);
                }
            }
        };
        // _req.onerror = (reason): void => {
        //     callback(false, reason)
        // }
    }
}
/////////淘宝小程序相关
/**
 * 获取临时路径
 * @param url cloud路径
 * @param callback
 */
function getTbTempUrl(url, onSuccess, onFail) {
    //@ts-ignore
    var cloud = getApp().cloud;
    //获取临时地址
    cloud.file.getTempFileURL({ fileId: [url] }).then(function (urls) {
        onSuccess(urls[0].url.replace('-internal', ''));
    }).catch(function (err) {
        //淘宝上的问题，直接打印吧
        // console.error(err)
        onFail && onFail(err);
    });
}
function downloadReadFile(url, onSuccess, onFail, type //"utf8" | "ArrayBuffer" = "ArrayBuffer"
) {
    if (type === void 0) { type = ResponseDataType.text; }
    //@ts-ignore
    var tbMy = my;
    tbMy.downloadFile({
        url: url,
        success: function (res) {
            var i = res.apFilePath; //临时地址是否有必要缓存下，如果读不到再考虑下载。
            tbMy.getFileSystemManager().readFile({
                filePath: i,
                encoding: type === ResponseDataType.arraybuffer ? "" : "utf8",
                success: function (r) {
                    //是json的需要反序列化一下
                    onSuccess(type == ResponseDataType.json ? JSON.parse(r.data) : r.data); //注意是r.data
                    // actions.load_viaProto(r.data, cb, failure);
                },
                fail: function (res) {
                    onFail && onFail(res);
                }
            });
        },
        fail: function (res) {
            onFail && onFail(res);
        },
    });
}
function tbLoad(url, onSuccess, onFail, type //"utf8" | "ArrayBuffer" = "ArrayBuffer"
) {
    if (type === void 0) { type = ResponseDataType.text; }
    //类似这种地址"cloud://A8673B47AAA58993A24A6718E203B967//dice.svga"
    if (url.indexOf("cloud://") == 0) {
        getTbTempUrl(url, function (src) {
            downloadReadFile(src, onSuccess, onFail, type);
        }, onFail);
    }
    else {
        downloadReadFile(url, onSuccess, onFail, type);
    }
}

/**
 * 每个texture都有一个BaseTexture，多数用于图集，texture可自身设置属性
 * 实际绘制用的都是BaseTexture
 * @class
 * @extends EventDispatcher
 */
var BaseTexture = /** @class */ (function (_super) {
    __extends(BaseTexture, _super);
    /**
     * @param {} [source] - 源数据
     * @param {SCALE_MODES}
     */
    function BaseTexture(source, scaleMode) {
        if (source === void 0) { source = null; }
        if (scaleMode === void 0) { scaleMode = SCALE_MODES.LINEAR; }
        var _this = _super.call(this) || this;
        _this._touchedId = 0;
        _this.width = 100;
        _this.height = 100;
        _this.scaleMode = scaleMode;
        _this.hasLoaded = false;
        _this._isLoading = false;
        _this.source = null;
        _this.imageType = null;
        _this.premultipliedAlpha = true;
        _this.imageUrl = null;
        _this.isPowerOfTwo = false;
        _this.mipmap = true;
        _this.wrapMode = WRAP_MODES.CLAMP;
        _this._glTextures = {};
        _this._enabledId = 0;
        _this.textureCacheIds = [];
        //有source要加载，构造函数不缓存baseTexture，要缓存用fromUrl
        if (source) {
            //是imageData
            if (source._data) {
                _this._sourceLoaded(source);
            }
            //是canvas
            else if (source.getContext) {
                _this._sourceLoaded(source);
            }
            else {
                if (source.complete) {
                    _this._sourceLoaded(source);
                    // this.dispatchEvent("loaded");//上面的方法会执行loaded
                }
                else {
                    var self = _this;
                    //会覆盖onload方法
                    source.onload = function () {
                        self._sourceLoaded(source);
                        // self.dispatchEvent("loaded");//上面的方法会执行loaded
                    };
                    //失败的
                    source.onerror = function () {
                        self.dispatchEvent("loaded");
                    };
                }
            }
        }
        return _this;
    }
    /**
     * 会触发更新事件
     * @fires BaseTexture#update
     */
    BaseTexture.prototype.update = function () {
        //尺寸重置
        this.width = this.source.width;
        this.height = this.source.height;
        //再来判断一次
        this.hasLoaded = this.width && this.height ? true : false;
        //判断是否是2的n次方
        this.isPowerOfTwo = isPow2(this.width) && isPow2(this.height);
        //触发绑定过的更新事件，比如webgl纹理更新
        this.dispatchEvent("update");
    };
    /**
     * 原先的_sourceChange改成了_sourceLoaded，且变成私有
     */
    BaseTexture.prototype._sourceLoaded = function (source) {
        //赋值
        this.source = source;
        //路径，暂时没用，需要时再处理，先找src 再path（基本没有）
        this.imageUrl = source.src || source.path || null;
        //更新类型,暂时没用，也没做，需要是处理
        this.imageType = this.source.type || null;
        //加载完成
        this.hasLoaded = true;
        //更新
        this.update();
        //触发事件
        this.dispatchEvent("loaded");
    };
    /**
     * 销毁 base texture
     * 基本不会销毁纹理
     */
    BaseTexture.prototype.destroy = function () {
        if (this.imageUrl) {
            delete TextureCache[this.imageUrl];
            this.imageUrl = null;
        }
        this.source = null;
        this.dispose();
        BaseTexture.removeFromCache(this);
        this.textureCacheIds = null;
    };
    /**
     * 用于释放gpu缓存，并不销毁纹理，需要时可再上传到GPU
     * @fires BaseTexture#dispose
     */
    BaseTexture.prototype.dispose = function () {
        //用于触发TextureManager中监听的
        this.dispatchEvent("dispose");
    };
    //辅助静态方法
    /**
     * 根据路径，会缓存baseTexture
     * @param {string} url  路径
     */
    BaseTexture.fromUrl = function (url) {
        if (BaseTextureCache[url])
            return BaseTextureCache[url];
        var baseTexture = new BaseTexture();
        GlobalLoader.loadImage(function (s, res) {
            if (s) {
                baseTexture._sourceLoaded(res);
                //添加进缓存
                if (url.indexOf('data:') !== 0)
                    BaseTexture.addToCache(baseTexture, url);
            }
            else {
                //失败的时候也需要派发加载事件
                baseTexture.dispatchEvent("loaded");
            }
        }, url);
        return baseTexture;
    };
    /**
     * 随便啥形式的，比如IImageData形式，
     * @param data
     */
    BaseTexture.fromData = function (data) {
        return new BaseTexture(data);
    };
    /**
     * 从离屏canvas创建的，会给canvas加唯一标识_canvasId，并缓存
     */
    BaseTexture.fromCanvas = function (canvas, origin) {
        if (origin === void 0) { origin = 'canvas'; }
        //标记canvasId
        if (!canvas["_canvasId"]) {
            canvas["_canvasId"] = origin + "_" + uid();
        }
        var baseTexture = BaseTextureCache[canvas["_canvasId"]];
        if (!baseTexture) {
            baseTexture = new BaseTexture(canvas);
            BaseTexture.addToCache(baseTexture, canvas["_canvasId"]);
        }
        return baseTexture;
    };
    /**
     * 根据图片
     * @param image
     */
    BaseTexture.fromImage = function (image) {
        //图片标签
        var imageUrl = image.src;
        var baseTexture = BaseTextureCache[imageUrl];
        if (!baseTexture) {
            baseTexture = new BaseTexture(image);
            //不缓存base64，如需要，设名字，手动缓存
            if (imageUrl && imageUrl.indexOf('data:') !== 0)
                BaseTexture.addToCache(baseTexture, imageUrl);
        }
        return baseTexture;
    };
    /**
     * 所有形式，图片路径，canvas标签，图片标签，或者数据
     * @param anything
     * @returns
     */
    BaseTexture.from = function (anything) {
        //路径
        if (typeof anything === 'string') {
            return BaseTexture.fromUrl(anything);
        }
        //@ts-ignore
        else if (anything._data) {
            //@ts-ignore
            return BaseTexture.fromData(anything);
        }
        //@ts-ignore canvas
        else if (anything.getContext) {
            //@ts-ignore
            return BaseTexture.fromCanvas(anything);
        }
        else {
            //@ts-ignore
            return BaseTexture.fromImage(anything);
        }
    };
    /**
     * 加入全局基础纹理缓存
     * @static
     * @param {BaseTexture} baseTexture
     * @param {string} id
     */
    BaseTexture.addToCache = function (baseTexture, id) {
        if (id) {
            if (baseTexture.textureCacheIds.indexOf(id) === -1) {
                baseTexture.textureCacheIds.push(id);
            }
            if (BaseTextureCache[id]) {
                //覆盖
                console.warn("rewrite cached baseTexture: " + id);
            }
            BaseTextureCache[id] = baseTexture;
        }
    };
    /**
     * 移除缓存
     * @static
     * @param {string|BaseTexture} baseTexture id或者BaseTexture
     * @return {BaseTexture|null} 移除的BaseTexture或null
     */
    BaseTexture.removeFromCache = function (baseTexture) {
        if (typeof baseTexture === 'string') {
            var baseTextureFromCache = BaseTextureCache[baseTexture];
            if (baseTextureFromCache) {
                var index = baseTextureFromCache.textureCacheIds.indexOf(baseTexture);
                if (index > -1) {
                    baseTextureFromCache.textureCacheIds.splice(index, 1);
                }
                delete BaseTextureCache[baseTexture];
                return baseTextureFromCache;
            }
        }
        else if (baseTexture && baseTexture.textureCacheIds) {
            for (var i = 0; i < baseTexture.textureCacheIds.length; ++i) {
                delete BaseTextureCache[baseTexture.textureCacheIds[i]];
            }
            baseTexture.textureCacheIds.length = 0;
            return baseTexture;
        }
        return null;
    };
    return BaseTexture;
}(EventDispatcher));

/**
 * Texture的uv
 * @class
 * @private
 */
var TextureUvs = /** @class */ (function () {
    /**
     * 用于记录图片的uv
     * 00.....10
     * .      .
     * .      .
     * 01.....11
     */
    function TextureUvs() {
        this.x0 = 0;
        this.y0 = 0;
        this.x1 = 1;
        this.y1 = 0;
        this.x2 = 1;
        this.y2 = 1;
        this.x3 = 0;
        this.y3 = 1;
        this.uvsUint32 = new Uint32Array(4);
        this.uvsFloat32 = new Float32Array(8);
    }
    /**
     * Sets the texture Uvs based on the given frame information.
     *
     * @private
     * @param {Rectangle} frame - The frame of the texture
     * @param {Rectangle} baseFrame - The base frame of the texture
     * @param {number} rotate - Rotation of frame, see {@link GroupD8}
     */
    TextureUvs.prototype.set = function (frame, baseFrame, rotate) {
        var tw = baseFrame.width;
        var th = baseFrame.height;
        if (rotate) {
            // width and height div 2 div baseFrame size
            var w2 = frame.width / 2 / tw;
            var h2 = frame.height / 2 / th;
            // coordinates of center
            var cX = (frame.x / tw) + w2;
            var cY = (frame.y / th) + h2;
            rotate = GroupD8.add(rotate, GroupD8.NW); // NW is top-left corner
            this.x0 = cX + (w2 * GroupD8.uX(rotate));
            this.y0 = cY + (h2 * GroupD8.uY(rotate));
            rotate = GroupD8.add(rotate, 2); // rotate 90 degrees clockwise
            this.x1 = cX + (w2 * GroupD8.uX(rotate));
            this.y1 = cY + (h2 * GroupD8.uY(rotate));
            rotate = GroupD8.add(rotate, 2);
            this.x2 = cX + (w2 * GroupD8.uX(rotate));
            this.y2 = cY + (h2 * GroupD8.uY(rotate));
            rotate = GroupD8.add(rotate, 2);
            this.x3 = cX + (w2 * GroupD8.uX(rotate));
            this.y3 = cY + (h2 * GroupD8.uY(rotate));
        }
        else {
            this.x0 = frame.x / tw;
            this.y0 = frame.y / th;
            this.x1 = (frame.x + frame.width) / tw;
            this.y1 = frame.y / th;
            this.x2 = (frame.x + frame.width) / tw;
            this.y2 = (frame.y + frame.height) / th;
            this.x3 = frame.x / tw;
            this.y3 = (frame.y + frame.height) / th;
        }
        this.uvsUint32[0] = (((this.y0 * 65535) & 0xFFFF) << 16) | ((this.x0 * 65535) & 0xFFFF);
        this.uvsUint32[1] = (((this.y1 * 65535) & 0xFFFF) << 16) | ((this.x1 * 65535) & 0xFFFF);
        this.uvsUint32[2] = (((this.y2 * 65535) & 0xFFFF) << 16) | ((this.x2 * 65535) & 0xFFFF);
        this.uvsUint32[3] = (((this.y3 * 65535) & 0xFFFF) << 16) | ((this.x3 * 65535) & 0xFFFF);
        this.uvsFloat32[0] = this.x0;
        this.uvsFloat32[1] = this.y0;
        this.uvsFloat32[2] = this.x1;
        this.uvsFloat32[3] = this.y1;
        this.uvsFloat32[4] = this.x2;
        this.uvsFloat32[5] = this.y2;
        this.uvsFloat32[6] = this.x3;
        this.uvsFloat32[7] = this.y3;
    };
    return TextureUvs;
}());

/**
 * 一张图片或图集的一部分，如果没有frame。默认整张图片
 *
 * eg
 * let texture = Texture.fromImage('assets/image.png');
 * let sprite1 = new Sprite(texture);
 * let sprite2 = new Sprite(texture);
 *
 * @class
 * @extends EventDispatcher
 */
var Texture = /** @class */ (function (_super) {
    __extends(Texture, _super);
    /**
     * @param {BaseTexture} baseTexture - The base texture source to create the texture from
     * @param {Rectangle} [frame] - The rectangle frame of the texture to show
     * @param {Rectangle} [orig] - The area of original texture
     * @param {Rectangle} [trim] - Trimmed rectangle of original texture
     * @param {number} [rotate] - indicates how the texture was rotated by texture packer. See {@link GroupD8}
     * @param {Point} [anchor] - Default anchor point used for sprite placement / rotation
     */
    function Texture(baseTexture, frame, orig, trim, rotate, anchor) {
        var _this = _super.call(this) || this;
        _this._instanceType = "Texture";
        _this.noFrame = false;
        if (!frame) {
            //标记没有固定的frame
            _this.noFrame = true;
            //frame初始化个
            frame = new Rectangle(0, 0, 1, 1);
        }
        //如果传入的是Texture，取其base
        if (baseTexture instanceof Texture)
            baseTexture = baseTexture.baseTexture;
        _this.baseTexture = baseTexture;
        _this._frame = frame;
        _this.trim = trim || null;
        _this.valid = false;
        _this._uvs = null;
        _this.orig = orig || frame; // new Rectangle(0, 0, 1, 1);
        _this._rotate = Number(rotate || 0);
        //对于canvas形式的判断hasLoaded有问题，导致不能监听update，hasLoaded还用于判断纹理是否可用（canvas宽高为0不可用），所以这里判断吧
        if (baseTexture.hasLoaded || (baseTexture.source && baseTexture.source.getContext)) {
            if (_this.noFrame) {
                frame = new Rectangle(0, 0, baseTexture.width, baseTexture.height);
                // if there is no frame we should monitor for any base texture changes..
                baseTexture.addEventListener('update', _this.onBaseTextureUpdated, _this);
            }
            _this.frame = frame;
        }
        else {
            baseTexture.once('loaded', _this.onBaseTextureLoaded, _this);
        }
        _this.defaultAnchor = anchor ? new Point(anchor.x, anchor.y) : new Point(0, 0);
        _this._updateID = 0;
        _this.transform = null;
        _this.textureCacheIds = [];
        return _this;
    }
    Object.defineProperty(Texture, "WHITE", {
        get: function () {
            if (!Texture._WHITE) {
                //白图纹理用canvas建
                var canvas = createCanvas();
                canvas.width = 16;
                canvas.height = 16;
                var context = canvas.getContext('2d');
                context.clearRect(0, 0, 16, 16); //淘宝小程序的问题，必须先调用过clearRect，否则有几率绘制无效
                context.fillStyle = 'white'; //淘宝小程序待测试
                context.fillRect(0, 0, 16, 16);
                //生成纹理
                var white = new Texture(new BaseTexture(canvas));
                //置空事件方法
                removeAllHandlers(white);
                removeAllHandlers(white.baseTexture);
                //缓存赋值
                Texture._WHITE = white;
            }
            return Texture._WHITE;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 更新方法，直接调用base的，source尺寸有改变，或内容有改变，基本用于Shape和TextField
     * 在base更新时会触发自己的
     */
    Texture.prototype.update = function () {
        this.baseTexture.update();
    };
    // 下面Loaded和Updated两个监听函数基本用于两种情况，不会用于图集中的纹理(除非图集还没加载好)
    // 1、canvas作为贴图需要监听尺寸变化，Shape里以及TextField里
    // 2、单张图片（如网络图片临时加载）需要监听尺寸变化，比如奖品图片，尺寸不一且未知
    /**
     *
     * @private
     * @param {BaseTexture} baseTexture - The base texture.
     */
    Texture.prototype.onBaseTextureLoaded = function (e /*,baseTexture: BaseTexture*/) {
        var baseTexture = e.target;
        this._updateID++;
        //执行这个函数意味着noFrame为true
        // TODO this code looks confusing.. boo to abusing getters and setters!
        if (this.noFrame) {
            if (baseTexture.source) { //加载成功了才修改frame和监听
                this.frame = new Rectangle(0, 0, baseTexture.width, baseTexture.height);
                //如果是没传过固定的frame就要监听了
                this.baseTexture.addEventListener('update', this.onBaseTextureUpdated, this);
            }
        }
        else {
            this.frame = this._frame;
        }
        //加载成功的时候有必要触发update吗？
        this.dispatchEvent("update");
        //加一个，监听texture，在BaseTexture加载完成后执行
        // Texture.from("asd.png").once("loaded",()=>{
        //     考虑是否有必要传参数，
        //     回调
        // })
        this.dispatchEvent("loaded");
    };
    /**
     *
     * @private
     * @param {BaseTexture} baseTexture - The base texture.
     */
    Texture.prototype.onBaseTextureUpdated = function (e /*,baseTexture*/) {
        var baseTexture = e.target;
        //标志纹理已更新
        this._updateID++;
        //只有尺寸需要
        this._frame.width = baseTexture.width;
        this._frame.height = baseTexture.height;
        this.orig.width = this._frame.width;
        this.orig.height = this._frame.height;
        this.valid = baseTexture.hasLoaded;
        this.dispatchEvent("update");
    };
    /**
     * 销毁
     */
    Texture.prototype.destroy = function () {
        if (this.baseTexture) {
            //考虑是否销毁baseTexture
            // if (destroyBase) {
            //     // delete the texture if it exists in the texture cache..
            //     // this only needs to be removed if the base texture is actually destroyed too..
            //     if (TextureCache[this.baseTexture.imageUrl]) {
            //         Texture.removeFromCache(this.baseTexture.imageUrl);
            //     }
            //     this.baseTexture.destroy();
            // }
            this.baseTexture.removeEventListener('update', this.onBaseTextureUpdated, this);
            this.baseTexture.removeEventListener('loaded', this.onBaseTextureLoaded, this);
            this.baseTexture = null;
        }
        this._frame = null;
        this._uvs = null;
        this.trim = null;
        this.orig = null;
        this.valid = false;
        Texture.removeFromCache(this);
        this.textureCacheIds = null;
    };
    /**
     * 克隆
     * @return {Texture} The new texture
     */
    Texture.prototype.clone = function () {
        return new Texture(this.baseTexture, this.frame, this.orig, this.trim, this.rotate, this.defaultAnchor);
    };
    /**
     * 更新uv，比如在frame改变或trim改变之后
     */
    Texture.prototype.updateUvs = function () {
        if (!this._uvs)
            this._uvs = new TextureUvs();
        this._uvs.set(this._frame, this.baseTexture, this.rotate);
        this._updateID++;
    };
    Object.defineProperty(Texture.prototype, "frame", {
        /**
          * The frame specifies the region of the base texture that this texture uses.
          * 手动修改frame时，而不是set赋值，比如frame.x=111,frame.width=333,需要手动调用updateUvs，不推荐这种方式修改
          * @member {Rectangle}
          */
        get: function () {
            return this._frame;
        },
        set: function (frame) {
            this._frame = frame;
            this.noFrame = false;
            var x = frame.x, y = frame.y, width = frame.width, height = frame.height;
            var xNotFit = x + width > this.baseTexture.width;
            var yNotFit = y + height > this.baseTexture.height;
            if (xNotFit || yNotFit) {
                var relationship = xNotFit && yNotFit ? 'and' : 'or';
                var errorX = "X: " + x + " + " + width + " = " + (x + width) + " > " + this.baseTexture.width;
                var errorY = "Y: " + y + " + " + height + " = " + (y + height) + " > " + this.baseTexture.height;
                throw new Error('Texture Error: frame does not fit inside the base Texture dimensions: '
                    + (errorX + " " + relationship + " " + errorY));
            }
            //标记是否可用
            this.valid = width && height && this.baseTexture.source && this.baseTexture.hasLoaded;
            //如果无裁切透明像素，无旋转，orig和frame完全一致
            if (!this.trim && !this.rotate)
                this.orig = frame;
            //如果可用，更新uv
            if (this.valid)
                this.updateUvs();
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Texture.prototype, "rotate", {
        /**
         * Indicates whether the texture is rotated inside the atlas
         * set to 2 to compensate for texture packer rotation
         * set to 6 to compensate for spine packer rotation
         * can be used to rotate or mirror sprites
         * See {@link GroupD8} for explanation
         *
         * @member {number}
         */
        get: function () {
            return this._rotate;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Texture.prototype, "width", {
        // set rotate(rotate: number) {
        //     if (this._rotate != rotate) {
        //         this._rotate = rotate;
        //         if (this.valid) this.updateUvs();
        //     }
        // }
        /**
         * 宽高都是纹理真实的宽高，不管trim
         * @member {number}
         */
        get: function () {
            return this.orig.width;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Texture.prototype, "height", {
        /**
         * 宽高都是纹理真实的宽高，不管trim
         * @member {number}
         */
        get: function () {
            return this.orig.height;
        },
        enumerable: false,
        configurable: true
    });
    //辅助方法
    /**
     * 会缓存进全局纹理
     * @param {string} url
     */
    Texture.fromUrl = function (url) {
        var texture = TextureCache[url];
        if (!texture) {
            texture = new Texture(BaseTexture.fromUrl(url));
            Texture.addToCache(texture, url);
        }
        return texture;
    };
    Texture.fromCanvas = function (canvas, origin) {
        if (origin === void 0) { origin = 'canvas'; }
        return new Texture(BaseTexture.fromCanvas(canvas, origin));
    };
    Texture.fromData = function (data) {
        return new Texture(BaseTexture.fromData(data));
    };
    Texture.fromImage = function (image) {
        var imageUrl = image.src;
        var texture = TextureCache[imageUrl];
        if (!texture) {
            texture = new Texture(BaseTexture.fromImage(image));
            if (imageUrl && imageUrl.indexOf('data:') !== 0)
                Texture.addToCache(texture, imageUrl);
        }
        return texture;
    };
    /**
     * 图片路径，canvas标签，图片标签，图片数据
     * @param anything
     * @returns
     */
    Texture.from = function (anything) {
        //路径
        if (typeof anything === 'string') {
            return Texture.fromUrl(anything);
        }
        //@ts-ignore
        else if (anything.data) {
            return Texture.fromData(anything);
        }
        //@ts-ignore canvas
        else if (anything.getContext) {
            //@ts-ignore
            return Texture.fromCanvas(anything);
        }
        else {
            //@ts-ignore
            return Texture.fromImage(anything);
        }
    };
    /**
     * 加入全局纹理缓存，TextureCache[name]调用
     * @static
     * @param {Texture} texture
     * @param {string} id
     */
    Texture.addToCache = function (texture, id) {
        if (id) {
            if (texture.textureCacheIds.indexOf(id) === -1) {
                texture.textureCacheIds.push(id);
            }
            if (TextureCache[id]) {
                //覆盖
                console.warn("rewrite cached texture: " + id);
            }
            TextureCache[id] = texture;
        }
    };
    /**
     * 从全局缓存中移除
     * @static
     * @param {string|Texture} texture - 纹理的id或纹理自身
     * @return {Texture} 返回移除的纹理
     */
    Texture.removeFromCache = function (texture) {
        if (typeof texture === 'string') {
            var textureFromCache = TextureCache[texture];
            if (textureFromCache) {
                var index = textureFromCache.textureCacheIds.indexOf(texture);
                if (index > -1) {
                    textureFromCache.textureCacheIds.splice(index, 1);
                }
                delete TextureCache[texture];
                return textureFromCache;
            }
        }
        else if (texture && texture.textureCacheIds) {
            for (var i = 0; i < texture.textureCacheIds.length; ++i) {
                // Check that texture matches the one being passed in before deleting it from the cache.
                if (TextureCache[texture.textureCacheIds[i]] === texture) {
                    delete TextureCache[texture.textureCacheIds[i]];
                }
            }
            texture.textureCacheIds.length = 0;
            return texture;
        }
        return null;
    };
    return Texture;
}(EventDispatcher));
//将事件置空，空纹理或白纹理不需要响应任何加载或更新事件
function removeAllHandlers(tex) {
    tex.destroy = function _emptyDestroy() { };
    tex.addEventListener = function _emptyOn() { };
    tex.once = function _emptyOnce() { };
    tex.dispatchEvent = function _emptyEmit() { };
    tex.removeEventListener = function _emptyOff() { };
}
/**
 * 空纹理，用于绑定webgl绑定空纹理
 * @static
 * @constant
 */
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
removeAllHandlers(Texture.EMPTY.baseTexture);
// /**
//  * 16*16的数据
//  */
// const whiteSource = {
//     _data: (function () {
//         var arr = []
//         for (var i = 0; i < 16 * 16 * 4; i++) {
//             arr.push(255);
//         }
//         return new Uint8Array(arr)
//     })(),
//     width: 16,
//     height: 16,
//     type: null,
//     path: null
// }
// /**
//  * 白色纹理，几何形状的纹理16*16
//  * 仅用于webgl模式的Graphics
//  * @static
//  * @constant
//  */
// Texture.WHITE = new Texture(new BaseTexture(whiteSource));
// removeAllHandlers(Texture.WHITE);
// removeAllHandlers(Texture.WHITE.baseTexture);
//用离屏canvas，否则canvas渲染模式用不了
// Texture.WHITE = (() => {
//     const canvas = createCanvas();
//     canvas.width = 16;
//     canvas.height = 16;
//     const context = canvas.getContext('2d');
//     context.clearRect(0, 0, 16, 16);//淘宝小程序的问题，必须先调用过clearRect，否则有几率绘制无效
//     context.fillStyle = 'white';//淘宝小程序待测试
//     context.fillRect(0, 0, 16, 16);
//     return new Texture(new BaseTexture(canvas));
// })();
// removeAllHandlers(Texture.WHITE);
// removeAllHandlers(Texture.WHITE.baseTexture);

var indices = new Uint16Array([0, 1, 2, 0, 2, 3]);
//临时矩阵
var tempMatrix$4;
/**
 * Sprite类，显示图片和容器功能
 * @class
 * @extends Container
 */
var Sprite = /** @class */ (function (_super) {
    __extends(Sprite, _super);
    /**
     * @param {Texture} texture
     */
    function Sprite(texture) {
        var _this = _super.call(this) || this;
        /**
         * 混色模式
         * @default BLEND_MODES.NORMAL
         */
        _this._blendMode = BLEND_MODES.NORMAL;
        /**
         * 是否使用像素检测，对于png图片透明区域检测很有效， 默认关闭，Shape继承后默认开启
         * @property hitTestByPixel
         * @type {boolean}
         */
        _this.hitTestByPixel = false;
        _this._instanceType = "Sprite";
        _this._anchorTexture = new ObservablePoint(_this._onAnchorUpdate, _this, (texture ? texture.defaultAnchor.x : 0), (texture ? texture.defaultAnchor.y : 0));
        _this._texture = null;
        _this._width = 0;
        _this._height = 0;
        _this._tint = null;
        _this._tintRGB = null;
        _this.tint = 0xFFFFFF;
        _this._cachedTint = 0xFFFFFF;
        _this._uvs = null;
        _this.texture = texture || Texture.EMPTY;
        _this._vertexData = new Float32Array(8);
        _this._vertexTrimmedData = null;
        _this._transformID = -1;
        _this._textureID = -1;
        _this._transformTrimmedID = -1;
        _this._textureTrimmedID = -1;
        // 批处理设置
        _this._indices = indices;
        // this.size = 4;
        // this.start = 0;
        _this.pluginName = 'sprite';
        return _this;
    }
    Object.defineProperty(Sprite.prototype, "blendMode", {
        //以后修改
        get: function () {
            return this._blendMode;
        },
        /**
         * 很多效果暂时无效，再查原因，先不能设置吧
         */
        set: function (value) {
            // if (value != this._blendMode) this._blendMode = value
        },
        enumerable: false,
        configurable: true
    });
    /**
     * texture更新时触发
     * @private
     */
    Sprite.prototype._onTextureUpdate = function () {
        //保证顶点要更新
        this._textureID = -1;
        this._textureTrimmedID = -1;
        this._cachedTint = 0xFFFFFF;
        //可用才赋值uv
        if (this._texture.valid)
            this._uvs = this._texture._uvs.uvsFloat32;
        //设置过宽高的话，就需要改变缩放值
        // so if _width is 0 then width was not set..
        if (this._width) {
            this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
        }
        if (this._height) {
            this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
        }
        //修改_localBoundsSelf
        this.updateLocalBoundsSelf();
        //包围盒id
        this._boundsID++;
    };
    /**
     * 当贴图锚点修改时
     *
     * @private
     */
    Sprite.prototype._onAnchorUpdate = function () {
        this._transformID = -1;
        this._transformTrimmedID = -1;
        //贴图锚点修改，也要修改自身盒子，因为鼠标点击有用到
        this.updateLocalBoundsSelf();
    };
    /**
     * 通过自身贴图修改自身盒子
     * 子类可修改，比如文本不需要padding的话，暂时还没做
     */
    Sprite.prototype.updateLocalBoundsSelf = function () {
        //修改_localBoundsSelf
        var width = this._texture.orig.width;
        var height = this._texture.orig.height;
        this._localBoundsSelf.x = -width * this.anchorTexture.x;
        this._localBoundsSelf.y = -height * this.anchorTexture.y;
        this._localBoundsSelf.width = width;
        this._localBoundsSelf.height = height;
    };
    /**
     * 01——23
     * |   |
     * 67——45
     * 计算全局的顶点数据
     */
    Sprite.prototype.calculateVertices = function () {
        if (this._transformID === this.transform._worldID && this._textureID === this._texture._updateID) {
            return;
        }
        this._transformID = this.transform._worldID;
        this._textureID = this._texture._updateID;
        var texture = this._texture;
        var wt = this.transform.worldMatrix;
        var a = wt.a;
        var b = wt.b;
        var c = wt.c;
        var d = wt.d;
        var tx = wt.tx;
        var ty = wt.ty;
        var vertexData = this._vertexData;
        var trim = texture.trim;
        var orig = texture.orig;
        var anchor = this._anchorTexture;
        var w0 = 0;
        var w1 = 0;
        var h0 = 0;
        var h1 = 0;
        if (trim) {
            // if the sprite is trimmed and is not a tilingsprite then we need to add the extra
            // space before transforming the sprite coords.
            //绘制永远根据frame，所以有trim过的，加个偏移
            w1 = trim.x - (anchor._x * orig.width);
            w0 = w1 + trim.width;
            h1 = trim.y - (anchor._y * orig.height);
            h0 = h1 + trim.height;
        }
        else {
            w1 = -anchor._x * orig.width;
            w0 = w1 + orig.width;
            h1 = -anchor._y * orig.height;
            h0 = h1 + orig.height;
        }
        // xy
        vertexData[0] = (a * w1) + (c * h1) + tx;
        vertexData[1] = (d * h1) + (b * w1) + ty;
        // xy
        vertexData[2] = (a * w0) + (c * h1) + tx;
        vertexData[3] = (d * h1) + (b * w0) + ty;
        // xy
        vertexData[4] = (a * w0) + (c * h0) + tx;
        vertexData[5] = (d * h0) + (b * w0) + ty;
        // xy
        vertexData[6] = (a * w1) + (c * h0) + tx;
        vertexData[7] = (d * h0) + (b * w1) + ty;
    };
    /**
     * 用于trim过的纹理，计算真实顶点位置，
     * 因为trim会裁切边缘透明像素，所以直接用orig的尺寸
     */
    Sprite.prototype.calculateTrimmedVertices = function () {
        if (!this._vertexTrimmedData) {
            this._vertexTrimmedData = new Float32Array(8);
        }
        else if (this._transformTrimmedID === this.transform._worldID && this._textureTrimmedID === this._texture._updateID) {
            return;
        }
        this._transformTrimmedID = this.transform._worldID;
        this._textureTrimmedID = this._texture._updateID;
        // lets do some special trim code!
        var texture = this._texture;
        var vertexData = this._vertexTrimmedData;
        var orig = texture.orig;
        var anchor = this._anchorTexture;
        // lets calculate the new untrimmed bounds..
        var wt = this.transform.worldMatrix;
        var a = wt.a;
        var b = wt.b;
        var c = wt.c;
        var d = wt.d;
        var tx = wt.tx;
        var ty = wt.ty;
        var w1 = -anchor._x * orig.width;
        var w0 = w1 + orig.width;
        var h1 = -anchor._y * orig.height;
        var h0 = h1 + orig.height;
        // xy
        vertexData[0] = (a * w1) + (c * h1) + tx;
        vertexData[1] = (d * h1) + (b * w1) + ty;
        // xy
        vertexData[2] = (a * w0) + (c * h1) + tx;
        vertexData[3] = (d * h1) + (b * w0) + ty;
        // xy
        vertexData[4] = (a * w0) + (c * h0) + tx;
        vertexData[5] = (d * h0) + (b * w0) + ty;
        // xy
        vertexData[6] = (a * w1) + (c * h0) + tx;
        vertexData[7] = (d * h0) + (b * w1) + ty;
    };
    /**
    * 自身webgl绘制方法
    * @private
    * @param {WebglRenderer} renderer
    */
    Sprite.prototype._renderWebGL = function (renderer) {
        //先计算顶点
        this.calculateVertices();
        renderer.batchManager.setObjectRenderer(renderer.plugins["batch"]);
        renderer.plugins["batch"].render(this);
    };
    /**
    * 自身canvas绘制方法
    * @private
    * @param {CanvasRenderer} renderer
    */
    Sprite.prototype._renderCanvas = function (renderer) {
        renderer.plugins[this.pluginName].render(this);
    };
    /**
     * 更新自己的bounds，计算全局
     * @private
     */
    Sprite.prototype._calculateBounds = function () {
        var trim = this._texture.trim;
        var orig = this._texture.orig;
        //无trim。或者trim的尺寸和orig相等
        if (!trim || (trim.width === orig.width && trim.height === orig.height)) {
            this.calculateVertices();
            Rectangle.createFromVertexData(this._bounds, this._vertexData);
        }
        else {
            //计算trimmed bounds...
            this.calculateTrimmedVertices();
            Rectangle.createFromVertexData(this._bounds, this._vertexTrimmedData);
        }
    };
    /**
     * 重写父类
     * @param {Rectangle} rect - The output rectangle.
     * @return {Rectangle} The bounds.
     */
    Sprite.prototype.getLocalBounds = function (rect) {
        //如果没有child，直接
        if (this.children.length === 0) {
            if (!rect) {
                rect = DisplayObject.temBounds;
            }
            //直接用_localBoundsSelf
            rect.copy(this._localBoundsSelf);
            return rect;
        }
        return _super.prototype.getLocalBounds.call(this, rect);
    };
    /**
     * 重写碰撞检测方法
     * @param globalPoint
     * @param isMouseEvent
     */
    Sprite.prototype.hitTestPoint = function (globalPoint, isMouseEvent) {
        if (isMouseEvent === void 0) { isMouseEvent = false; }
        //不可见，直接返回
        if (!this.visible)
            return null;
        //mouseChildren和mouseEnable在各自继承里判断，container和displayObject里都有
        //如果以后加缓存成位图，另写
        var hitDisplayObject;
        //先检查子级，因为子级层级更高
        hitDisplayObject = _super.prototype.hitTestPoint.call(this, globalPoint, isMouseEvent);
        //子级已有，返回
        if (hitDisplayObject)
            return hitDisplayObject;
        //检查自己，包围盒检测。
        hitDisplayObject = this.displayObjectHitTestPoint(globalPoint, isMouseEvent);
        //自身包围盒检测不通过
        if (!hitDisplayObject)
            return null;
        //不是像素检测的，直接返回对象
        if (!this.hitTestByPixel)
            return hitDisplayObject;
        ///////////////下面开始像素检测//////////////////
        var _a = this, texture = _a.texture, _anchorTexture = _a._anchorTexture;
        var orig = texture.orig, frame = texture.frame, trim = texture.trim, rotate = texture.rotate, baseTexture = texture.baseTexture;
        //拷贝一个，以防globalPoint被修改
        var p = DisplayObject._bp.copy(globalPoint);
        //鼠标事件转换下
        if (isMouseEvent)
            p = this.globalToLocal(p);
        //贴图锚点偏移
        p.x += _anchorTexture.x * orig.width;
        p.y += _anchorTexture.y * orig.height;
        //先判断是否在trim外面，orig已经在displayObjectHitTestPoint检测过了
        if (trim) {
            //不在里面直接返回false
            if (!trim.isPointIn(p))
                return null;
            //还需要做点啥，转到trim中
            p.x -= trim.x;
            p.y -= trim.y;
        }
        //如果纹理带旋转，转换p，暂时就2和6有效，所以texture的rotate暂时只给图集用，自己千万别擅自修改
        if (rotate) {
            if (!tempMatrix$4)
                tempMatrix$4 = new Matrix();
            // tempMatrix.set(1, 0, 0, 1, 0, 0)
            //其实只有2和6的话，直接能写出矩阵，但是先这样吧，先注释吧，后续都能算了再统一到GroupD8里计算
            // GroupD8.matrixAppendRotationInv(tempMatrix, GroupD8.inv(rotate));
            //还需要平移
            if (rotate == 2) {
                tempMatrix$4.set(0, 1, -1, 0, frame.width, 0);
            }
            else if (rotate == 6) { //待测试
                tempMatrix$4.set(0, -1, 1, 0, 0, frame.height);
            }
            tempMatrix$4.transformPoint(p.x, p.y, p);
        }
        //处理frame的偏移
        p.x += frame.x;
        p.y += frame.y;
        //数据形式，直接取
        if (baseTexture.source._data) {
            //对应点的像素
            if (baseTexture.source._data[((Math.round(p.y - 1)) * baseTexture.source.width + Math.round(p.x)) * 4 - 1] > 0) {
                return hitDisplayObject;
            }
            return null;
        }
        //像素检测
        var ctx = getBackupCanvasCtx();
        ctx.setTransform(1, 0, 0, 1, 0, 0); //先移动位置，否则颜色清除有问题,原先修改尺寸就不用
        ctx.clearRect(0, 0, 1, 1);
        ctx.setTransform(1, 0, 0, 1, -p.x, -p.y);
        ctx.drawImage(baseTexture.source, 0, 0);
        //取imageData对象
        var imageData = ctx.getImageData(0, 0, 1, 1);
        //容错处理(暂时淘宝小程序bug，安卓有可能取到的imageData是undefined)，按照存在处理
        if (!imageData || !imageData.data)
            return hitDisplayObject;
        // console.log("alpha:", imageData.data[3])
        //像素透明度不为0
        if (imageData.data[3] > 0)
            return hitDisplayObject;
        return null;
    };
    /**
     * 销毁
     */
    Sprite.prototype.destroy = function () {
        _super.prototype.destroy.call(this);
        //相应texture移除监听
        this._texture.removeEventListener('update', this._onTextureUpdate, this);
        this._anchorTexture = null;
        this._texture = null;
        this._indices = null;
        this._uvs = null;
        this._vertexData = null;
        this._vertexTrimmedData = null;
        //对于canvas可能有调色缓存
        if (this["tintedTexture"])
            this["tintedTexture"] = null;
    };
    Object.defineProperty(Sprite.prototype, "width", {
        /**
         * 重写Container父类
         * 获取texture的宽度和缩放乘积
         * @member {number}
         */
        get: function () {
            return Math.abs(this.scale.x) * this._texture.orig.width;
        },
        /**
         * 重写父级
         * 根据纹理宽度设置自身缩放x到设置的数值
         */
        set: function (value) {
            var s = sign(this.scale.x) || 1;
            this.scale.x = s * value / this._texture.orig.width;
            this._width = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Sprite.prototype, "height", {
        /**
         * 获取texture的高度和缩放乘积
         * @member {number}
         */
        get: function () {
            return Math.abs(this.scale.y) * this._texture.orig.height;
        },
        /**
         * 根据纹理高度设置自身缩放y到设置的数值
         */
        set: function (value) {
            var s = sign(this.scale.y) || 1;
            this.scale.y = s * value / this._texture.orig.height;
            this._height = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Sprite.prototype, "anchorTexture", {
        /**
         * 0，0标识左上角，0.5，0.5表示中间，1，1表示右下角
         * @member {ObservablePoint}
         */
        get: function () {
            return this._anchorTexture;
        },
        /**
         * 设置贴图锚点，copy方法，只要value存在x、y字段就行
         */
        set: function (value) {
            this._anchorTexture.copy(value);
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Sprite.prototype, "texture", {
        /**
         * 获取纹理
         * @member {Texture}
         */
        get: function () {
            return this._texture === Texture.EMPTY ? null : this._texture; //考虑是否返回null
        },
        /**
         * 设置纹理
         */
        set: function (value) {
            if (this._texture === value || this.destroyed) { //如果已经被销毁了,不用再执行下面,
                return;
            }
            //如果存在原贴图，且还没加载好，移除监听_onTextureUpdate；
            // if (this._texture != Texture.EMPTY &&
            //     this._texture != null &&
            //     !this._texture.baseTexture.hasLoaded) this._texture.removeEventListener('update', this._onTextureUpdate, this);
            //原来的纹理，其实直接全都要移除，
            if (this._texture) {
                this._texture.removeEventListener('update', this._onTextureUpdate, this);
            }
            //赋值
            this._texture = value || Texture.EMPTY;
            this._textureID = -1;
            this._textureTrimmedID = -1;
            this._cachedTint = 0xFFFFFF;
            if (value) {
                if (value.baseTexture.hasLoaded) {
                    this._onTextureUpdate();
                }
                // else {
                //     value.once('update', this._onTextureUpdate, this);//只会监听一次
                // }
                //都监听下，其实没加载的纹理图片纹理确实只需要监听一次，这里先不管了，存在性能问题，当一个纹理被大量对象使用时，事件数组会很大，导致遍历性能，TODO
                value.addEventListener('update', this._onTextureUpdate, this);
            }
            else {
                //624修改。如果置空纹理，_localBoundsSelf置空
                // this.updateLocalBoundsSelf();
                //20211201修改，这样修改如果设置过width和height的，内部会通过设置scale保留，从而依旧能点击到
                this._onTextureUpdate();
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Sprite.prototype, "tint", {
        /**
         * 获取调色
         */
        get: function () {
            return this._tint;
        },
        /**
         * 设置调色
         */
        set: function (value) {
            if (value === this._tint)
                return;
            this._tint = value;
            this._tintRGB = (value >> 16) + (value & 0xff00) + ((value & 0xff) << 16);
        },
        enumerable: false,
        configurable: true
    });
    //一些静态类方法
    /**
     * 网络图片
     * @param url 链接
     * @return Sprite实例
     */
    Sprite.fromUrl = function (url) {
        return new Sprite(Texture.fromUrl(url));
    };
    /**
     * TextureCache缓存里取得frameId，通常图集里得名字
     * @static
     * @param {string} frameId - The frame Id of the texture in the cache
     * @return {Sprite} A new Sprite using a texture from the texture cache matching the frameId
     */
    Sprite.fromFrame = function (frameId) {
        var texture = TextureCache[frameId];
        if (!texture) {
            // throw new Error(`The frameId "${frameId}" does not exist in the texture cache`);
            console.warn("TextureCache hasn\u2018t texture " + frameId);
        }
        return new Sprite(texture);
    };
    return Sprite;
}(Container));

/**
 * 鼠标事件类
 * @class MouseEvent
 * @extends Event
 * @public
 * @since 1.0.0
 */
var MouseEvent = /** @class */ (function (_super) {
    __extends(MouseEvent, _super);
    /**
     * @method MouseEvent
     * @public
     * @since 1.0.0
     * @param {string} type
     */
    function MouseEvent(type) {
        var _this = _super.call(this, type) || this;
        /**
         * 鼠标事件时canvas实际尺寸坐标x点
         * @property clientX
         * @public
         * @since 1.0.0
         * @type {number}
         */
        _this.clientX = 0;
        /**
         * 鼠标事件时canvas实际尺寸坐标y点
         * @property clientY
         * @public
         * @since 1.0.0
         * @type {number}
         */
        _this.clientY = 0;
        /**
         * 鼠标事件时stage上坐标x点
         * @property stageX
         * @public
         * @since 1.0.0
         * @type {number}
         */
        _this.stageX = 0;
        /**
         * 鼠标事件时stage上坐标y点
         * @property stageY
         * @public
         * @since 1.0.0
         * @type {number}
         */
        _this.stageY = 0;
        /**
         * 鼠标事件时显示对象本地坐标x点
         * @property localX
         * @public
         * @since 1.0.0
         * @type {number}
         */
        _this.localX = 0;
        /**
         * 鼠标事件时显示对象本地坐标y点
         * @property localY
         * @public
         * @since 1.0.0
         * @type {number}
         */
        _this.localY = 0;
        /**
         * 鼠标事件的终点对象，注意区分target
         * @property currentTarget
         * @public
         * @since 1.0.0
         * @type{DisplayObject}
         * @default null
         */
        _this.currentTarget = null;
        /**
         * 鼠标事件的手指唯一标识
         * @property identifier
         * @type {number}
         * @since 1.1.2
         * @public
         */
        _this.identifier = 0;
        _this._instanceType = "MouseEvent";
        return _this;
    }
    /**
     * 销毁
     */
    MouseEvent.prototype.destroy = function () {
        //清除相应的数据引用
        var s = this;
        s.currentTarget = null;
        _super.prototype.destroy.call(this);
    };
    /**
     * 鼠标按下事件
     * @property MOUSE_DOWN
     * @static
     * @public
     * @since 1.0.0
     * @type {string}
     */
    MouseEvent.MOUSE_DOWN = "onMouseDown";
    /**
     * 鼠标抬起事件
     * @property MOUSE_UP
     * @static
     * @public
     * @since 1.0.0
     * @type {string}
     */
    MouseEvent.MOUSE_UP = "onMouseUp";
    /**
     * 鼠标点击事件
     * @property CLICK
     * @static
     * @public
     * @since 1.0.0
     * @type {string}
     */
    MouseEvent.CLICK = "onMouseClick";
    /**
     * 鼠标移动事件
     * @property MOUSE_MOVE
     * @static
     * @public
     * @since 1.0.0
     * @type {string}
     */
    MouseEvent.MOUSE_MOVE = "onMouseMove";
    /**
     * 鼠标移入到显示对象上里触发的事件
     * @property MOUSE_OVER
     * @static
     * @public
     * @since 1.0.0
     * @type {string}
     */
    MouseEvent.MOUSE_OVER = "onMouseOver";
    /**
     * 鼠标移出显示对象边界触发的事件
     * @property MOUSE_OUT
     * @static
     * @public
     * @since 1.0.0
     * @type {string}
     */
    MouseEvent.MOUSE_OUT = "onMouseOut";
    return MouseEvent;
}(Event));

/**
 *
 * @class
 */
var BatchDrawCall = /** @class */ (function () {
    function BatchDrawCall() {
        this.textures = [];
        // this.ids = [];
        this.blend = 0;
        this.textureCount = 0;
        this.start = 0;
        this.size = 0;
        this.type = DRAW_MODES.TRIANGLES;
    }
    return BatchDrawCall;
}());

/**
 * Base for a common object renderer that can be used as a system renderer plugin.
 * 基础渲染插件基类
 */
var ObjectRenderer = /** @class */ (function () {
    function ObjectRenderer(renderer) {
        this.renderer = renderer;
        //监听
        this.renderer.addEventListener('onContextChange', this.onContextChange, this);
    }
    /**
     * Generic method called when there is a WebGL context change.
     *
     * @param {WebGLRenderingContext} gl new webgl context
     */
    ObjectRenderer.prototype.onContextChange = function () {
        // do some codes init!
    };
    /**
     * Starts the renderer and sets the shader
     *
     */
    ObjectRenderer.prototype.start = function () {
        // set the shader..
    };
    /**
     * Stops the renderer
     *
     */
    ObjectRenderer.prototype.stop = function () {
        this.flush();
    };
    /**
     * Stub method for rendering content and emptying the current batch.
     *
     */
    ObjectRenderer.prototype.flush = function () {
        // flush!
    };
    /**
     * Renders an object
     *
     */
    ObjectRenderer.prototype.render = function (object) {
        // render the object
    };
    /**
     * Generic destroy methods to be overridden by the subclass
     */
    ObjectRenderer.prototype.destroy = function () {
        this.renderer.removeEventListener('onContextChange', this.onContextChange, this);
        this.renderer = null;
    };
    return ObjectRenderer;
}());

/**
 * Helper class to create a webGL Context
 * 创建webgl上下文
 * @param canvas {HTMLCanvasElement} the canvas element that we will get the context from
 * @param options {Object} An options object that gets passed in to the canvas element containing the context attributes,
 *                         see https://developer.mozilla.org/en/docs/Web/API/HTMLCanvasElement/getContext for the options available
 * @return {WebGLRenderingContext} the WebGL context
 */
function createContext(canvas, options) {
    var gl = canvas.getContext('webgl', options) ||
        canvas.getContext('experimental-webgl', options);
    if (!gl) {
        // fail, not able to get a context
        throw new Error('This browser does not support webGL. Try using the canvas renderer');
    }
    //@ts-ignore
    return gl;
}

var fragTemplate$2 = [
    'precision mediump float;',
    'void main(void){',
    'float test = 0.1;',
    '%forloop%',
    'gl_FragColor = vec4(0.0);',
    '}',
].join('\n');
/**
 * 检查最大纹理数是否合法
 * @param maxIfs
 * @param gl
 */
function checkMaxIfStatementsInShader(maxIfs, gl) {
    var createTempContext = !gl;
    // @if DEBUG
    if (maxIfs === 0) {
        throw new Error('Invalid value of `0` passed to `checkMaxIfStatementsInShader`');
    }
    // @endif
    if (createTempContext) {
        var tinyCanvas = createCanvas(); //document.createElement('canvas');
        tinyCanvas.width = 1;
        tinyCanvas.height = 1;
        gl = createContext(tinyCanvas);
    }
    var shader = gl.createShader(gl.FRAGMENT_SHADER);
    while (true) // eslint-disable-line no-constant-condition
     {
        var fragmentSrc = fragTemplate$2.replace(/%forloop%/gi, generateIfTestSrc(maxIfs));
        gl.shaderSource(shader, fragmentSrc);
        gl.compileShader(shader);
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
            maxIfs = (maxIfs / 2) | 0;
        }
        else {
            // valid!
            break;
        }
    }
    if (createTempContext) {
        // get rid of context
        if (gl.getExtension('WEBGL_lose_context')) {
            gl.getExtension('WEBGL_lose_context').loseContext();
        }
    }
    return maxIfs;
}
function generateIfTestSrc(maxIfs) {
    var src = '';
    for (var i = 0; i < maxIfs; ++i) {
        if (i > 0) {
            src += '\nelse ';
        }
        if (i < maxIfs - 1) {
            src += "if(test == " + i + ".0){}";
        }
    }
    return src;
}

/**
 * 批处理用buffer数据
 */
var BatchBuffer = /** @class */ (function () {
    /**
     * @param {number} size - The size of the buffer in bytes.
     */
    function BatchBuffer(size) {
        this.vertices = new ArrayBuffer(size);
        this.float32View = new Float32Array(this.vertices);
        this.uint32View = new Uint32Array(this.vertices);
    }
    /**
     * Destroys the buffer.
     *
     */
    BatchBuffer.prototype.destroy = function () {
        this.vertices = null;
        this.float32View = null;
        this.uint32View = null;
        this.positions = null;
        this.uvs = null;
        this.colors = null;
    };
    return BatchBuffer;
}());

/**
 * Helper class to create a WebGL Texture
 * 用于创建WebGL Texture
 * @class
 * @memberof glCore
 * @param gl {WebGLRenderingContext} The current WebGL context
 * @param width {number} the width of the texture
 * @param height {number} the height of the texture
 * @param format {number} the pixel format of the texture. defaults to gl.RGBA
 * @param type {number} the gl type of the texture. defaults to gl.UNSIGNED_BYTE
 */
var GLTexture = /** @class */ (function () {
    function GLTexture(gl, width, height, format, type) {
        /**
         * Use a data source and uploads this texture to the GPU
         * 数据类型的纹理
         * @param data {TypedArray} the data to upload to the texture
         * @param width {number} the new width of the texture
         * @param height {number} the new height of the texture
         */
        this.uploadData = function (data, width, height) {
            this.bind();
            var gl = this.gl;
            if (data instanceof Float32Array) {
                if (!FLOATING_POINT_AVAILABLE) {
                    var ext = gl.getExtension("OES_texture_float");
                    if (ext) {
                        FLOATING_POINT_AVAILABLE = true;
                    }
                    else {
                        throw new Error('floating point textures not available');
                    }
                }
                this.type = gl.FLOAT;
            }
            else {
                // TODO support for other types
                this.type = this.type || gl.UNSIGNED_BYTE;
            }
            // what type of data?
            gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, this.premultiplyAlpha);
            if (width !== this.width || height !== this.height) {
                gl.texImage2D(gl.TEXTURE_2D, 0, this.format, width, height, 0, this.format, this.type, data || null);
            }
            else {
                gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, this.format, this.type, data || null);
            }
            this.width = width;
            this.height = height;
            //	texSubImage2D
        };
        this.gl = gl;
        this.texture = gl.createTexture();
        // some settings..
        this.mipmap = false;
        this.premultiplyAlpha = false;
        this.width = width || -1;
        this.height = height || -1;
        /**
         * The pixel format of the texture. defaults to gl.RGBA
         *
         * @member {Number}
         */
        this.format = format || gl.RGBA;
        /**
         * The gl type of the texture. defaults to gl.UNSIGNED_BYTE
         *
         * @member {Number}
         */
        this.type = type || gl.UNSIGNED_BYTE;
    }
    /**
     * Uploads this texture to the GPU
     * GPU存储纹理数据
     * @param source {HTMLImageElement|ImageData|HTMLVideoElement} the source image of the texture
     */
    GLTexture.prototype.upload = function (source) {
        this.bind();
        var gl = this.gl;
        //设置是否对纹理进行预乘透明通道
        gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, this.premultiplyAlpha);
        var newWidth = source.videoWidth || source.width;
        var newHeight = source.videoHeight || source.height;
        if (newHeight !== this.height || newWidth !== this.width) {
            //https://developer.mozilla.org/zh-CN/docs/Web/API/WebGLRenderingContext/texImage2D
            gl.texImage2D(gl.TEXTURE_2D, 0, this.format, this.format, this.type, source);
        }
        else {
            //https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/texSubImage2D
            gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, this.format, this.type, source);
        }
        // if the source is a video, we need to use the videoWidth / videoHeight properties as width / height will be incorrect.
        this.width = newWidth;
        this.height = newHeight;
    };
    /**
     * Binds the texture
     * 绑定纹理，不传location表示不激活额外纹理，绑定的纹理位置与原状态相同
     * @param  location
     */
    GLTexture.prototype.bind = function (location) {
        var gl = this.gl;
        if (location !== undefined) {
            gl.activeTexture(gl.TEXTURE0 + location);
        }
        gl.bindTexture(gl.TEXTURE_2D, this.texture);
    };
    /**
     * Unbinds the texture
     * 解除纹理绑定，解除位置与原状态相同
     */
    GLTexture.prototype.unbind = function () {
        var gl = this.gl;
        gl.bindTexture(gl.TEXTURE_2D, null);
    };
    /**
     * @param linear {Boolean} if we want to use linear filtering or nearest neighbour interpolation
     * 缩小的纹理像素 按线性插值，还是按钮邻近原则
     */
    GLTexture.prototype.minFilter = function (linear) {
        var gl = this.gl;
        this.bind();
        if (this.mipmap) {
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, linear ? gl.LINEAR_MIPMAP_LINEAR : gl.NEAREST_MIPMAP_NEAREST);
        }
        else {
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, linear ? gl.LINEAR : gl.NEAREST);
        }
    };
    /**
     * @param linear {Boolean} if we want to use linear filtering or nearest neighbour interpolation
     * 放大的纹理像素 按线性插值，还是按钮邻近原则
     */
    GLTexture.prototype.magFilter = function (linear) {
        var gl = this.gl;
        this.bind();
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, linear ? gl.LINEAR : gl.NEAREST);
    };
    /**
     * Enables mipmapping
     * 生成缩小的纹理集，只能在图片宽高满足2的指数时使用
     */
    GLTexture.prototype.enableMipmap = function () {
        var gl = this.gl;
        this.bind();
        this.mipmap = true;
        gl.generateMipmap(gl.TEXTURE_2D);
    };
    /**
     * Enables linear filtering
     * 设置线性
     */
    GLTexture.prototype.enableLinearScaling = function () {
        this.minFilter(true);
        this.magFilter(true);
    };
    /**
     * Enables nearest neighbour interpolation
     * 设置邻近
     */
    GLTexture.prototype.enableNearestScaling = function () {
        this.minFilter(false);
        this.magFilter(false);
    };
    /**
     * Enables clamping on the texture so WebGL will not repeat it
     * 如果纹理不满足2的指数时必设，以边缘像素延申
     */
    GLTexture.prototype.enableWrapClamp = function () {
        var gl = this.gl;
        this.bind();
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    };
    /**
     * Enable tiling on the texture
     * 允许纹理重复，地砖模式
     */
    GLTexture.prototype.enableWrapRepeat = function () {
        var gl = this.gl;
        this.bind();
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
    };
    /**
     * 镜像形式重复
     */
    GLTexture.prototype.enableWrapMirrorRepeat = function () {
        var gl = this.gl;
        this.bind();
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.MIRRORED_REPEAT);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);
    };
    /**
     * Destroys this texture
     */
    GLTexture.prototype.destroy = function () {
        var gl = this.gl;
        //TODO
        gl.deleteTexture(this.texture);
    };
    /**
     * 从图片数据创建纹理
     * @static
     * @param gl {WebGLRenderingContext} The current WebGL context
     * @param source {HTMLImageElement|ImageData} the source image of the texture
     * @param premultiplyAlpha {Boolean} If we want to use pre-multiplied alpha
     */
    GLTexture.fromSource = function (gl, source, premultiplyAlpha) {
        var texture = new GLTexture(gl);
        texture.premultiplyAlpha = premultiplyAlpha || false;
        texture.upload(source);
        return texture;
    };
    /**
     * @static
     * @param gl {WebGLRenderingContext} The current WebGL context
     * @param data {TypedArray} the data to upload to the texture
     * @param width {number} the new width of the texture
     * @param height {number} the new height of the texture
     */
    GLTexture.fromData = function (gl, data, width, height) {
        //console.log(data, width, height);
        var texture = new GLTexture(gl);
        texture.uploadData(data, width, height);
        return texture;
    };
    return GLTexture;
}());
var FLOATING_POINT_AVAILABLE = false;

var EMPTY_ARRAY_BUFFER = new ArrayBuffer(0);
/**
 * 用于创建webGL buffer，顶点和索引专用
 * @class
 * @memberof glCore
 * @param gl {WebGLRenderingContext} The current WebGL rendering context
 * @param type {gl.ARRAY_BUFFER | gl.ELEMENT_ARRAY_BUFFER} @mat
 * @param data {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} an array of data
 * @param drawType {gl.STATIC_DRAW|gl.DYNAMIC_DRAW|gl.STREAM_DRAW}
 */
var GLBuffer = /** @class */ (function () {
    function GLBuffer(gl, type, data, drawType) {
        /**
         * Destroys the buffer
         *
         */
        this.destroy = function () {
            this.gl.deleteBuffer(this.buffer);
        };
        this.gl = gl;
        this.buffer = gl.createBuffer();
        this.type = type || gl.ARRAY_BUFFER;
        this.drawType = drawType || gl.STATIC_DRAW;
        this.data = EMPTY_ARRAY_BUFFER;
        if (data) {
            this.upload(data);
        }
        this._updateID = 0;
    }
    /**
     * 上传数据
     * Uploads the buffer to the GPU
     * @param data {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} an array of data to upload
     * @param offset {Number} if only a subset of the data should be uploaded, this is the amount of data to subtract
     * @param dontBind {Boolean} whether to bind the buffer before uploading it  是否不绑定buffer
     */
    GLBuffer.prototype.upload = function (data, offset, dontBind) {
        // todo - needed?
        if (!dontBind)
            this.bind();
        var gl = this.gl;
        data = data || this.data;
        offset = offset || 0;
        if (this.data.byteLength >= data.byteLength) {
            gl.bufferSubData(this.type, offset, data);
        }
        else {
            gl.bufferData(this.type, data, this.drawType);
        }
        this.data = data;
    };
    /**
     * Binds the buffer
     * 状态机接下来使用的buffer
     *
     */
    GLBuffer.prototype.bind = function () {
        var gl = this.gl;
        gl.bindBuffer(this.type, this.buffer);
    };
    /**
     * 创建顶点缓存
     * @param gl
     * @param data
     * @param drawType
     */
    GLBuffer.createVertexBuffer = function (gl, data, drawType) {
        return new GLBuffer(gl, gl.ARRAY_BUFFER, data, drawType);
    };
    /**
     * 创建索引缓存
     * @param gl
     * @param data
     * @param drawType
     */
    GLBuffer.createIndexBuffer = function (gl, data, drawType) {
        return new GLBuffer(gl, gl.ELEMENT_ARRAY_BUFFER, data, drawType);
    };
    GLBuffer.create = function (gl, type, data, drawType) {
        return new GLBuffer(gl, type, data, drawType);
    };
    return GLBuffer;
}());

// var GL_MAP = {};
/**
 * 连接attribute变量与分配给它的缓冲区对象，两种方式，与顶点着色器通信核心方法
 * @param gl {WebGLRenderingContext} The current WebGL context
 * @param attribs {*}
 * @param state {*}
 */
function setVertexAttribArrays(gl, attribs, state) {
    var i;
    if (state) {
        var tempAttribState = state.tempAttribState, attribState = state.attribState;
        for (i = 0; i < tempAttribState.length; i++) {
            tempAttribState[i] = false;
        }
        // set the new attribs
        for (i = 0; i < attribs.length; i++) {
            tempAttribState[attribs[i].attribute.location] = true;
        }
        for (i = 0; i < attribState.length; i++) {
            if (attribState[i] !== tempAttribState[i]) {
                attribState[i] = tempAttribState[i];
                if (state.attribState[i]) {
                    gl.enableVertexAttribArray(i);
                }
                else {
                    gl.disableVertexAttribArray(i);
                }
            }
        }
    }
    else {
        for (i = 0; i < attribs.length; i++) {
            var attrib = attribs[i];
            gl.enableVertexAttribArray(attrib.attribute.location);
        }
    }
}

// state object//
/**
 * Helper class to work with WebGL VertexArrayObjects (vaos)
 * Only works if WebGL extensions are enabled (they usually are)
 * 核心类VAOs
 * @class
 * @memberof glCore
 * @param gl {WebGLRenderingContext} The current WebGL rendering context
 */
var VertexArrayObject = /** @class */ (function () {
    function VertexArrayObject(gl, state) {
        this.nativeVaoExtension = null;
        //不要求必须使用原生时，基本都支持扩展
        if (!VertexArrayObject.FORCE_NATIVE) {
            this.nativeVaoExtension = gl.getExtension('OES_vertex_array_object') ||
                gl.getExtension('MOZ_OES_vertex_array_object') ||
                gl.getExtension('WEBKIT_OES_vertex_array_object');
        }
        this.nativeState = state;
        if (this.nativeVaoExtension) {
            this.nativeVao = this.nativeVaoExtension.createVertexArrayOES();
            var maxAttribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
            // VAO - overwrite the state..
            this.nativeState = {
                tempAttribState: new Array(maxAttribs),
                attribState: new Array(maxAttribs)
            };
        }
        this.gl = gl;
        this.attributes = [];
        this.indexBuffer = null;
        this.dirty = false;
    }
    /**
     * Binds the buffer
     * 绑定数据
     */
    VertexArrayObject.prototype.bind = function () {
        if (this.nativeVao) {
            this.nativeVaoExtension.bindVertexArrayOES(this.nativeVao);
            if (this.dirty) {
                this.dirty = false;
                this.activate();
                return this;
            }
            if (this.indexBuffer) {
                this.indexBuffer.bind();
            }
        }
        else {
            this.activate();
        }
        return this;
    };
    /**
     * Unbinds the buffer
     * 解绑数据
     */
    VertexArrayObject.prototype.unbind = function () {
        if (this.nativeVao) {
            this.nativeVaoExtension.bindVertexArrayOES(null);
        }
        return this;
    };
    /**
     * Uses this vao
     * 激活vao
     */
    VertexArrayObject.prototype.activate = function () {
        var gl = this.gl;
        var lastBuffer = null;
        for (var i = 0; i < this.attributes.length; i++) {
            var attrib = this.attributes[i];
            if (lastBuffer !== attrib.buffer) {
                attrib.buffer.bind();
                lastBuffer = attrib.buffer;
            }
            // gl.vertexAttribPointer(attrib.attribute.location,
            //     attrib.attribute.size,
            //     attrib.type || gl.FLOAT,
            //     attrib.normalized || false,
            //     attrib.stride || 0,
            //     attrib.start || 0);
            attrib.attribute.pointer(attrib.type || gl.FLOAT, attrib.normalized || false, attrib.stride || 0, attrib.start || 0);
        }
        setVertexAttribArrays(gl, this.attributes, this.nativeState);
        if (this.indexBuffer) {
            this.indexBuffer.bind();
        }
        return this;
    };
    /**
     * 添加attribute
     * @param buffer     {gl.GLBuffer}
     * @param attribute  {*}
     * @param type       {String}
     * @param normalized {Boolean}
     * @param stride     {Number}
     * @param start      {Number}
     * @param name       {string} 名字，用于移除，否则不需要传
     */
    VertexArrayObject.prototype.addAttribute = function (buffer, attribute, type, normalized, stride, start, name) {
        this.attributes.push({
            buffer: buffer,
            attribute: attribute,
            location: attribute.location,
            type: type || this.gl.FLOAT,
            normalized: normalized || false,
            stride: stride || 0,
            start: start || 0,
            name: name,
        });
        this.dirty = true;
        return this;
    };
    /**
     * 移除attribute，暂时attributes是数组，是否考虑变成对象，现在按数组遍历移除，到时重名可能还有问题TODO
     * @param name
     * @param onlyOne
     */
    VertexArrayObject.prototype.removeAttribute = function (name, onlyOne) {
        if (onlyOne === void 0) { onlyOne = true; }
        var len = this.attributes.length;
        for (var i = len - 1; i >= 0; i--) { //倒序
            var attr = this.attributes[i];
            if (attr.name === name) { //同名移除
                this.attributes.splice(i, 1); //从数组移除
                //有改动，标记下
                this.dirty = true;
                //只需要移除一个就break
                if (onlyOne)
                    break;
            }
        }
        return this;
    };
    /**
     * 添加索引数据
     * @param buffer   {gl.GLBuffer}
     */
    VertexArrayObject.prototype.addIndex = function (buffer /*, options*/) {
        this.indexBuffer = buffer;
        this.dirty = true;
        return this;
    };
    /**
     * Unbinds this vao and disables it
     * 解绑废弃vao
     */
    VertexArrayObject.prototype.clear = function () {
        // var gl = this.gl;
        // TODO - should this function unbind after clear?
        // for now, no but lets see what happens in the real world!
        if (this.nativeVao) {
            this.nativeVaoExtension.bindVertexArrayOES(this.nativeVao);
        }
        this.attributes.length = 0;
        this.indexBuffer = null;
        return this;
    };
    /**
     * 执行绘制
     * @param type  {Number} gl.TRIANGLES\gl.TRIANGLE_STRIP等
     * @param size  {Number} 个数
     * @param start {Number} 偏移
     */
    VertexArrayObject.prototype.draw = function (type, size, start) {
        var gl = this.gl;
        if (this.indexBuffer) {
            //有索引 https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/drawElements
            gl.drawElements(type, size || this.indexBuffer.data.length, gl.UNSIGNED_SHORT, (start || 0) * 2);
        }
        else {
            //无索引 https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/drawArrays
            // TODO need a better way to calculate size..
            gl.drawArrays(type, start || 0, size || this.getSize());
        }
        return this;
    };
    /**
     * Destroy this vao
     */
    VertexArrayObject.prototype.destroy = function () {
        // lose references
        this.gl = null;
        this.indexBuffer = null;
        this.attributes = null;
        this.nativeState = null;
        if (this.nativeVao) {
            this.nativeVaoExtension.deleteVertexArrayOES(this.nativeVao);
        }
        this.nativeVaoExtension = null;
        this.nativeVao = null;
    };
    VertexArrayObject.prototype.getSize = function () {
        var attrib = this.attributes[0];
        // return attrib.buffer.data.length / ((attrib.stride / 4) || attrib.attribute.size);
        //ArrayBuffer没有length，要不要考虑0？
        return (attrib.buffer.data.length || attrib.buffer.data.byteLength / 4) / ((attrib.stride / 4) || attrib.attribute.size);
    };
    /**
    * Some devices behave a bit funny when using the newer extensions (im looking at you ipad 2!)
    * If you find on older devices that things have gone a bit weird then set this to true.
    */
    /**
     * Lets the VAO know if you should use the WebGL extension or the native methods.
     * Some devices behave a bit funny when using the newer extensions (im looking at you ipad 2!)
     * If you find on older devices that things have gone a bit weird then set this to true.
     * @static
     * @property {Boolean} FORCE_NATIVE
     */
    VertexArrayObject.FORCE_NATIVE = false;
    return VertexArrayObject;
}());

/**
 * Helper class to create a webGL Framebuffer
 * 帧缓存，暂时不使用，renderTarget里用，主要用于滤镜处理
 *
 * @class
 * @memberof glCore
 * @param gl {WebGLRenderingContext} The current WebGL rendering context
 * @param width {Number} the width of the drawing area of the frame buffer
 * @param height {Number} the height of the drawing area of the frame buffer
 */
var GLFramebuffer = /** @class */ (function () {
    function GLFramebuffer(gl, width, height) {
        this.gl = gl;
        this.framebuffer = gl.createFramebuffer();
        this.stencil = null;
        this.texture = null;
        this.width = width || 100;
        this.height = height || 100;
    }
    /**
     * Adds a texture to the frame buffer
     * @param texture {glCore.GLTexture}
     */
    GLFramebuffer.prototype.enableTexture = function (texture) {
        var gl = this.gl;
        this.texture = texture || new GLTexture(gl);
        this.texture.bind();
        //gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA,  this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
        this.bind();
        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture.texture, 0);
    };
    /**
     * Initialises the stencil buffer
     */
    GLFramebuffer.prototype.enableStencil = function () {
        if (this.stencil)
            return;
        var gl = this.gl;
        this.stencil = gl.createRenderbuffer();
        gl.bindRenderbuffer(gl.RENDERBUFFER, this.stencil);
        // TODO.. this is depth AND stencil?
        gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, this.stencil);
        gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, this.width, this.height);
    };
    /**
     * Erases the drawing area and fills it with a colour
     * @param  r {Number} the red value of the clearing colour
     * @param  g {Number} the green value of the clearing colour
     * @param  b {Number} the blue value of the clearing colour
     * @param  a {Number} the alpha value of the clearing colour
     */
    GLFramebuffer.prototype.clear = function (r, g, b, a) {
        this.bind();
        var gl = this.gl;
        gl.clearColor(r, g, b, a);
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    };
    /**
     * Binds the frame buffer to the WebGL context
     */
    GLFramebuffer.prototype.bind = function () {
        var gl = this.gl;
        gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
    };
    /**
     * Unbinds the frame buffer to the WebGL context
     */
    GLFramebuffer.prototype.unbind = function () {
        var gl = this.gl;
        gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    };
    /**
     * Resizes the drawing area of the buffer to the given width and height
     * @param  width  {Number} the new width
     * @param  height {Number} the new height
     */
    GLFramebuffer.prototype.resize = function (width, height) {
        var gl = this.gl;
        this.width = width;
        this.height = height;
        if (this.texture) {
            this.texture.uploadData(null, width, height);
        }
        if (this.stencil) {
            // update the stencil buffer width and height
            gl.bindRenderbuffer(gl.RENDERBUFFER, this.stencil);
            gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width, height);
        }
    };
    /**
     * Destroys this buffer
     */
    GLFramebuffer.prototype.destroy = function () {
        var gl = this.gl;
        //TODO
        if (this.texture) {
            this.texture.destroy();
        }
        gl.deleteFramebuffer(this.framebuffer);
        this.gl = null;
        this.stencil = null;
        this.texture = null;
    };
    /**
     * Creates a frame buffer with a texture containing the given data
     * @static
     * @param gl {WebGLRenderingContext} The current WebGL rendering context
     * @param width {Number} the width of the drawing area of the frame buffer
     * @param height {Number} the height of the drawing area of the frame buffer
     * @param data {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} an array of data
     */
    GLFramebuffer.createRGBA = function (gl, width, height, data) {
        // var texture = GLTexture.fromData(gl, null, width, height);
        var texture = GLTexture.fromData(gl, data || null, width, height);
        texture.enableNearestScaling();
        texture.enableWrapClamp();
        //now create the framebuffer object and attach the texture to it.
        var fbo = new GLFramebuffer(gl, width, height);
        fbo.enableTexture(texture);
        //加上了，待测试
        fbo.enableStencil(); // get this back on soon!
        //fbo.enableStencil(); // get this back on soon!
        fbo.unbind();
        return fbo;
    };
    /**
     * Creates a frame buffer with a texture containing the given data
     * @static
     * @param gl {WebGLRenderingContext} The current WebGL rendering context
     * @param width {Number} the width of the drawing area of the frame buffer
     * @param height {Number} the height of the drawing area of the frame buffer
     * @param data {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} an array of data
     */
    GLFramebuffer.createFloat32 = function (gl, width, height, data) {
        // create a new texture..
        var texture = GLTexture.fromData(gl, data, width, height);
        texture.enableNearestScaling();
        texture.enableWrapClamp();
        //now create the framebuffer object and attach the texture to it.
        var fbo = new GLFramebuffer(gl, width, height);
        fbo.enableTexture(texture);
        fbo.unbind();
        return fbo;
    };
    return GLFramebuffer;
}());

/**
 * 编译着色器程序
 * @param gl {WebGLRenderingContext} The current WebGL context {WebGLProgram}
 * @param vertexSrc  The vertex shader source as an array of strings.顶点着色器
 * @param fragmentSrc  The fragment shader source as an array of strings.片元着色器
 * @param attributeLocations {Object} An attribute location map that lets you manually set the attribute locations
 * @return {WebGLProgram} the shader program 返回着色器程序
 */
function compileProgram(gl, vertexSrc, fragmentSrc, attributeLocations) {
    var glVertShader = compileShader(gl, gl.VERTEX_SHADER, vertexSrc);
    var glFragShader = compileShader(gl, gl.FRAGMENT_SHADER, fragmentSrc);
    var program = gl.createProgram();
    gl.attachShader(program, glVertShader);
    gl.attachShader(program, glFragShader);
    // optionally, set the attributes manually for the program rather than letting WebGL decide..
    if (attributeLocations) {
        for (var i in attributeLocations) {
            gl.bindAttribLocation(program, attributeLocations[i], i);
        }
    }
    gl.linkProgram(program);
    // if linking fails, then log and cleanup
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
        console.error('Error: Could not initialize shader.');
        console.error('gl.VALIDATE_STATUS', gl.getProgramParameter(program, gl.VALIDATE_STATUS));
        console.error('gl.getError()', gl.getError());
        // if there is a program info log, log it
        if (gl.getProgramInfoLog(program) !== '') {
            console.warn('Warning: gl.getProgramInfoLog()', gl.getProgramInfoLog(program));
        }
        gl.deleteProgram(program);
        program = null;
    }
    // clean up some shaders
    gl.deleteShader(glVertShader);
    gl.deleteShader(glFragShader);
    return program;
}
/**
 * 创建shader
 * @private
 * @param gl {WebGLRenderingContext} The current WebGL context {WebGLProgram}
 * @param type {Number} the type, can be either VERTEX_SHADER or FRAGMENT_SHADER
 * @param vertexSrc {string|string[]} The vertex shader source as an array of strings.
 * @return {WebGLShader} the shader
 */
var compileShader = function (gl, type, src) {
    var shader = gl.createShader(type);
    gl.shaderSource(shader, src);
    gl.compileShader(shader);
    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        console.error(src);
        console.error(gl.getShaderInfoLog(shader));
        return null;
    }
    return shader;
};

function mapType(gl, type) {
    if (!GL_TABLE) {
        var typeNames = Object.keys(GL_TO_GLSL_TYPES);
        GL_TABLE = {};
        for (var i = 0; i < typeNames.length; ++i) {
            var tn = typeNames[i];
            GL_TABLE[gl[tn]] = GL_TO_GLSL_TYPES[tn];
        }
    }
    return GL_TABLE[type];
}
var GL_TABLE = null;
var GL_TO_GLSL_TYPES = {
    'FLOAT': 'float',
    'FLOAT_VEC2': 'vec2',
    'FLOAT_VEC3': 'vec3',
    'FLOAT_VEC4': 'vec4',
    'INT': 'int',
    'INT_VEC2': 'ivec2',
    'INT_VEC3': 'ivec3',
    'INT_VEC4': 'ivec4',
    'BOOL': 'bool',
    'BOOL_VEC2': 'bvec2',
    'BOOL_VEC3': 'bvec3',
    'BOOL_VEC4': 'bvec4',
    'FLOAT_MAT2': 'mat2',
    'FLOAT_MAT3': 'mat3',
    'FLOAT_MAT4': 'mat4',
    'SAMPLER_2D': 'sampler2D'
};

/**
 * @class
 * @memberof glCore.shader
 * @param type {String}
 * @return {Number}
 */
function mapSize(type) {
    return GLSL_TO_SIZE[type];
}
var GLSL_TO_SIZE = {
    'float': 1,
    'vec2': 2,
    'vec3': 3,
    'vec4': 4,
    'int': 1,
    'ivec2': 2,
    'ivec3': 3,
    'ivec4': 4,
    'bool': 1,
    'bvec2': 2,
    'bvec3': 3,
    'bvec4': 4,
    'mat2': 4,
    'mat3': 9,
    'mat4': 16,
    'sampler2D': 1
};

/**
 * Extracts the attributes获取attributes属性
 * @class
 * @memberof glCore.shader
 * @param gl {WebGLRenderingContext} The current WebGL rendering context
 * @param program {WebGLProgram} The shader program to get the attributes from
 * @return attributes {Object}
 */
function extractAttributes(gl, program) {
    var attributes = {};
    //所有激活的ATTRIBUTES
    var totalAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
    for (var i = 0; i < totalAttributes; i++) {
        var attribData = gl.getActiveAttrib(program, i);
        var type = mapType(gl, attribData.type);
        attributes[attribData.name] = {
            type: type,
            size: mapSize(type),
            location: gl.getAttribLocation(program, attribData.name),
            //TODO - make an attribute object
            pointer: function (type, normalized, stride, start) {
                if (type === void 0) { type = gl.FLOAT; }
                if (normalized === void 0) { normalized = false; }
                if (stride === void 0) { stride = 0; }
                if (start === void 0) { start = 0; }
                // console.log(this.location)
                gl.vertexAttribPointer(this.location, this.size, type, normalized, stride, start);
            }
        };
    }
    return attributes;
}

/**
 * @class
 * @memberof glCore.shader
 * @param type {String} Type of value
 * @param size {Number}
 */
function defaultValue(type, size) {
    switch (type) {
        case 'float':
            return 0;
        case 'vec2':
            return new Float32Array(2 * size);
        case 'vec3':
            return new Float32Array(3 * size);
        case 'vec4':
            return new Float32Array(4 * size);
        case 'int':
        case 'sampler2D':
            return 0;
        case 'ivec2':
            return new Int32Array(2 * size);
        case 'ivec3':
            return new Int32Array(3 * size);
        case 'ivec4':
            return new Int32Array(4 * size);
        case 'bool':
            return false;
        case 'bvec2':
            return booleanArray(2 * size);
        case 'bvec3':
            return booleanArray(3 * size);
        case 'bvec4':
            return booleanArray(4 * size);
        case 'mat2':
            return new Float32Array([1, 0,
                0, 1]);
        case 'mat3':
            return new Float32Array([1, 0, 0,
                0, 1, 0,
                0, 0, 1]);
        case 'mat4':
            return new Float32Array([1, 0, 0, 0,
                0, 1, 0, 0,
                0, 0, 1, 0,
                0, 0, 0, 1]);
    }
}
var booleanArray = function (size) {
    var array = new Array(size);
    for (var i = 0; i < array.length; i++) {
        array[i] = false;
    }
    return array;
};

/**
 * Extracts the uniforms 获取uniforms属性
 * @class
 * @memberof glCore.shader
 * @param gl {WebGLRenderingContext} The current WebGL rendering context
 * @param program {WebGLProgram} The shader program to get the uniforms from
 * @return uniforms {Object} ，所有uniform的集合
 * 每个uniform的格式
 * {
 *  type: uniform的类型，'float','vec2'等等
 *	size: uniformData.size,决定uniform赋值用什么方法
 *	location: WebGLUniformLocation,uniform变量的存储地址
 *	value: 默认值
 * }
 */
function extractUniforms$1(gl, program) {
    var uniforms = {};
    var totalUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
    for (var i = 0; i < totalUniforms; i++) {
        var uniformData = gl.getActiveUniform(program, i);
        var name = uniformData.name.replace(/\[.*?\]/, "");
        var type = mapType(gl, uniformData.type);
        uniforms[name] = {
            type: type,
            size: uniformData.size,
            location: gl.getUniformLocation(program, name),
            value: defaultValue(type, uniformData.size)
        };
    }
    return uniforms;
}

/**
 * 给shader source设置precision
 * Sets the float precision on the shader. If the precision is already present this function will do nothing
 * @param {string} src       the shader source
 * @param {string} precision The float precision of the shader. Options are 'lowp', 'mediump' or 'highp'.
 *
 * @return {string} modified shader source
 */
function setPrecision(src, precision) {
    if (src.substring(0, 9) !== 'precision') {
        return 'precision ' + precision + ' float;\n' + src;
    }
    return src;
}

/**
 * 使uniform能通过赋值直接和着色器程序通信
 * @class
 * @memberof glCore.shader
 * @param gl {WebGLRenderingContext} The current WebGL rendering context
 * @param uniforms {Array} @mat ?
 * @return attributes {Object}
 */
function generateUniformAccessObject(gl, uniformData) {
    // this is the object we will be sending back.
    // an object hierachy will be created for structs
    var uniforms = { data: {} };
    uniforms["gl"] = gl;
    var uniformKeys = Object.keys(uniformData);
    for (var i = 0; i < uniformKeys.length; i++) {
        var fullName = uniformKeys[i];
        var nameTokens = fullName.split('.');
        var name = nameTokens[nameTokens.length - 1];
        var uniformGroup = getUniformGroup(nameTokens, uniforms);
        var uniform = uniformData[fullName];
        uniformGroup.data[name] = uniform;
        uniformGroup.gl = gl;
        Object.defineProperty(uniformGroup, name, {
            get: generateGetter(name),
            set: generateSetter(name, uniform)
        });
    }
    return uniforms;
}
var generateGetter = function (name) {
    return function () {
        return this.data[name].value;
    };
};
var GLSL_SINGLE_SETTERS = {
    float: function setSingleFloat(gl, location, value) { gl.uniform1f(location, value); },
    vec2: function setSingleVec2(gl, location, value) { gl.uniform2f(location, value[0], value[1]); },
    vec3: function setSingleVec3(gl, location, value) { gl.uniform3f(location, value[0], value[1], value[2]); },
    vec4: function setSingleVec4(gl, location, value) { gl.uniform4f(location, value[0], value[1], value[2], value[3]); },
    int: function setSingleInt(gl, location, value) { gl.uniform1i(location, value); },
    ivec2: function setSingleIvec2(gl, location, value) { gl.uniform2i(location, value[0], value[1]); },
    ivec3: function setSingleIvec3(gl, location, value) { gl.uniform3i(location, value[0], value[1], value[2]); },
    ivec4: function setSingleIvec4(gl, location, value) { gl.uniform4i(location, value[0], value[1], value[2], value[3]); },
    bool: function setSingleBool(gl, location, value) { gl.uniform1i(location, value); },
    bvec2: function setSingleBvec2(gl, location, value) { gl.uniform2i(location, value[0], value[1]); },
    bvec3: function setSingleBvec3(gl, location, value) { gl.uniform3i(location, value[0], value[1], value[2]); },
    bvec4: function setSingleBvec4(gl, location, value) { gl.uniform4i(location, value[0], value[1], value[2], value[3]); },
    mat2: function setSingleMat2(gl, location, value) { gl.uniformMatrix2fv(location, false, value); },
    mat3: function setSingleMat3(gl, location, value) { gl.uniformMatrix3fv(location, false, value); },
    mat4: function setSingleMat4(gl, location, value) { gl.uniformMatrix4fv(location, false, value); },
    sampler2D: function setSingleSampler2D(gl, location, value) { gl.uniform1i(location, value); },
};
var GLSL_ARRAY_SETTERS = {
    float: function setFloatArray(gl, location, value) { gl.uniform1fv(location, value); },
    vec2: function setVec2Array(gl, location, value) { gl.uniform2fv(location, value); },
    vec3: function setVec3Array(gl, location, value) { gl.uniform3fv(location, value); },
    vec4: function setVec4Array(gl, location, value) { gl.uniform4fv(location, value); },
    int: function setIntArray(gl, location, value) { gl.uniform1iv(location, value); },
    ivec2: function setIvec2Array(gl, location, value) { gl.uniform2iv(location, value); },
    ivec3: function setIvec3Array(gl, location, value) { gl.uniform3iv(location, value); },
    ivec4: function setIvec4Array(gl, location, value) { gl.uniform4iv(location, value); },
    bool: function setBoolArray(gl, location, value) { gl.uniform1iv(location, value); },
    bvec2: function setBvec2Array(gl, location, value) { gl.uniform2iv(location, value); },
    bvec3: function setBvec3Array(gl, location, value) { gl.uniform3iv(location, value); },
    bvec4: function setBvec4Array(gl, location, value) { gl.uniform4iv(location, value); },
    sampler2D: function setSampler2DArray(gl, location, value) { gl.uniform1iv(location, value); },
    //添加矩阵数组
    mat4: function setMat4Array(gl, location, value) { gl.uniformMatrix4fv(location, false, value); },
};
function generateSetter(name, uniform) {
    return function (value) {
        this.data[name].value = value;
        var location = this.data[name].location;
        if (uniform.size === 1) {
            GLSL_SINGLE_SETTERS[uniform.type](this.gl, location, value);
        }
        else {
            // glslSetArray(gl, location, type, value) {
            GLSL_ARRAY_SETTERS[uniform.type](this.gl, location, value);
        }
    };
}
function getUniformGroup(nameTokens, uniform) {
    var cur = uniform;
    for (var i = 0; i < nameTokens.length - 1; i++) {
        var o = cur[nameTokens[i]] || { data: {} };
        cur[nameTokens[i]] = o;
        cur = o;
    }
    return cur;
}

/**
 * Helper class to create a webGL Shader
 * 创建webgl shader用，里面主要用到attributes和uniforms
 * @class
 * @memberof glCore
 * @param gl {WebGLRenderingContext}
 * @param vertexSrc {string|string[]} The vertex shader source as an array of strings.
 * @param fragmentSrc {string|string[]} The fragment shader source as an array of strings.
 * @param precision {string} The float precision of the shader. Options are 'lowp', 'mediump' or 'highp'.
 * @param attributeLocations {object} A key value pair showing which location eact attribute should sit eg {position:0, uvs:1}
 */
var GLShader = /** @class */ (function () {
    function GLShader(gl, vertexSrc, fragmentSrc, precision, attributeLocations) {
        this.gl = gl;
        if (precision) {
            vertexSrc = setPrecision(vertexSrc, precision);
            fragmentSrc = setPrecision(fragmentSrc, precision);
        }
        // First compile the program..
        this.program = compileProgram(gl, vertexSrc, fragmentSrc, attributeLocations);
        // next extract the attributes
        this.attributes = extractAttributes(gl, this.program);
        this.uniformData = extractUniforms$1(gl, this.program);
        this.uniforms = generateUniformAccessObject(gl, this.uniformData);
    }
    /**
     * Uses this shader
     * 状态机当前使用的shader
     * @return {glCore.GLShader} Returns itself.
     */
    GLShader.prototype.bind = function () {
        this.gl.useProgram(this.program);
        return this;
    };
    /**
     * Destroys this shader
     * TODO
     */
    GLShader.prototype.destroy = function () {
        this.attributes = null;
        this.uniformData = null;
        this.uniforms = null;
        var gl = this.gl;
        gl.deleteProgram(this.program);
    };
    return GLShader;
}());

//顶点着色器程序
var VSHADER_SOURCE = "precision highp float;" +
    "attribute vec2 aVertexPosition;" +
    "attribute vec2 aTextureCoord;" +
    "attribute vec4 aColor;" +
    "attribute float aTextureId;" +
    "uniform mat3 projectionMatrix;" +
    // "uniform mat3 modelMatrix;" +
    "varying vec2 vTextureCoord;" +
    "varying vec4 vColor;" +
    "varying float vTextureId;" +
    "void main(void){" +
    "gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);" +
    // "gl_Position = vec4((projectionMatrix *modelMatrix* vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);" +
    "vTextureCoord = aTextureCoord;" +
    "vTextureId = aTextureId;" +
    "vColor = aColor;" +
    "}";
//片元着色器程序
var fragTemplate$1 = [
    'precision mediump float;',
    'varying vec2 vTextureCoord;',
    'varying vec4 vColor;',
    'varying float vTextureId;',
    'uniform sampler2D uSamplers[%count%];',
    'void main(void){',
    'vec4 color;',
    'float textureId = floor(vTextureId+0.5);',
    '%forloop%',
    'gl_FragColor = color * vColor;',
    '}',
].join('\n');
/**
 * 创建批处理专用着色器，核心，切换纹理
 * @param gl
 * @param maxTextures 最大纹理数
 */
function generateMultiTextureShader(gl, maxTextures) {
    // const vertexSrc = readFileSync(join(__dirname, './texture.vert'), 'utf8');
    var fragmentSrc = fragTemplate$1;
    fragmentSrc = fragmentSrc.replace(/%count%/gi, maxTextures);
    fragmentSrc = fragmentSrc.replace(/%forloop%/gi, generateSampleSrc(maxTextures));
    // console.log(fragmentSrc)
    var shader = new GLShader(gl, VSHADER_SOURCE, fragmentSrc);
    var sampleValues = [];
    for (var i = 0; i < maxTextures; i++) {
        sampleValues[i] = i;
    }
    shader.bind();
    shader.uniforms["uSamplers"] = sampleValues;
    // console.log(fragmentSrc)
    return shader;
}
function generateSampleSrc(maxTextures) {
    var src = '';
    src += '\n';
    src += '\n';
    for (var i = 0; i < maxTextures; i++) {
        if (i > 0) {
            src += '\nelse ';
        }
        if (i < maxTextures - 1) {
            src += "if(textureId == " + i + ".0)";
        }
        src += '\n{';
        src += "\n\tcolor = texture2D(uSamplers[" + i + "], vTextureCoord);";
        src += '\n}';
    }
    src += '\n';
    src += '\n';
    return src;
}

/**
 * 矫正混色模式，因为有预乘alpha的
 * @private
 * @return {Array<number[]>} Mapped modes.
 */
function mapPremultipliedBlendModes() {
    var pm = [];
    var npm = [];
    for (var i = 0; i < 32; i++) {
        pm[i] = i;
        npm[i] = i;
    }
    pm[BLEND_MODES.NORMAL_NPM] = BLEND_MODES.NORMAL;
    pm[BLEND_MODES.ADD_NPM] = BLEND_MODES.ADD;
    pm[BLEND_MODES.SCREEN_NPM] = BLEND_MODES.SCREEN;
    npm[BLEND_MODES.NORMAL] = BLEND_MODES.NORMAL_NPM;
    npm[BLEND_MODES.ADD] = BLEND_MODES.ADD_NPM;
    npm[BLEND_MODES.SCREEN] = BLEND_MODES.SCREEN_NPM;
    var array = [];
    //0是非预乘alpha的
    array.push(npm);
    //1是预乘alpha的
    array.push(pm);
    return array;
}
//导出矫正后的
var premultiplyBlendMode = mapPremultipliedBlendModes();

var TICK = 0;
/**
 * 批处理核心渲染插件
 *
 * @class
 * @extends ObjectRenderer
 */
var BatchRenderer = /** @class */ (function (_super) {
    __extends(BatchRenderer, _super);
    function BatchRenderer(renderer) {
        var _this = _super.call(this, renderer) || this;
        /**
         * 每个点
         * Number of values sent in the vertex buffer.
         * aVertexPosition(2), aTextureCoord(2), aColor(1), aTextureId(1) = 6
         *
         * @member {number}
         */
        _this.vertSize = 6;
        /**
         * The size of the vertex information in bytes.
         *
         * @member {number}
         */
        _this.vertByteSize = _this.vertSize * 4;
        /**
         * The number of images in the SpriteRenderer before it flushes.
         *
         * @member {number}
         */
        _this.size = 2000 * 4; // settings.SPRITE_BATCH_SIZE; // 2000 is a nice balance between mobile / desktop
        _this.currentSize = 0;
        _this.currentIndexSize = 0;
        // the total number of bytes in our batch
        // let numVerts = this.size * 4 * this.vertByteSize;
        _this.aBuffers = {};
        _this.iBuffers = {};
        _this.shader = null;
        _this.currentIndex = 0;
        _this.groups = [];
        for (var k = 0; k < _this.size / 4; k++) {
            _this.groups[k] = new BatchDrawCall();
        }
        _this.elements = [];
        _this.vertexBuffers = [];
        _this.indexBuffers = [];
        _this.vaos = [];
        _this.vaoMax = 2;
        _this.vertexCount = 0;
        _this.renderer.addEventListener('onPreRender', _this.onPreRender, _this);
        return _this;
        // this.state = State.for2d();深度检测去掉
    }
    /**
     * Sets up the renderer context and necessary buffers.
     */
    BatchRenderer.prototype.onContextChange = function () {
        var gl = this.renderer.gl;
        {
            // step 1: first check max textures the GPU can handle.
            this.MAX_TEXTURES = Math.min(gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS), 16);
            // step 2: check the maximum number of if statements the shader can have too..
            this.MAX_TEXTURES = checkMaxIfStatementsInShader(this.MAX_TEXTURES, gl);
        }
        // generate generateMultiTextureProgram, may be a better move?
        this.shader = generateMultiTextureShader(gl, this.MAX_TEXTURES);
        // we use the second shader as the first one depending on your browser may omit aTextureId
        // as it is not used by the shader so is optimized out.
        this.renderer.bindVao(null);
        var attrs = this.shader.attributes;
        for (var i = 0; i < this.vaoMax; i++) {
            /* eslint-disable max-len */
            var vertexBuffer = this.vertexBuffers[i] = GLBuffer.createVertexBuffer(gl, null, gl.STREAM_DRAW);
            var indexBuffer = this.indexBuffers[i] = GLBuffer.createIndexBuffer(gl, null, gl.STREAM_DRAW);
            // build the vao object that will render..
            var vao = this.renderer.createVao()
                .addIndex(indexBuffer)
                .addAttribute(vertexBuffer, attrs.aVertexPosition, gl.FLOAT, false, this.vertByteSize, 0)
                // .addAttribute(vertexBuffer, attrs.aTextureCoord, gl.UNSIGNED_SHORT, true, this.vertByteSize, 2 * 4)
                // .addAttribute(vertexBuffer, attrs.aColor, gl.UNSIGNED_BYTE, true, this.vertByteSize, 3 * 4);
                .addAttribute(vertexBuffer, attrs.aTextureCoord, gl.FLOAT, true, this.vertByteSize, 2 * 4) //这里uv改成两位了
                .addAttribute(vertexBuffer, attrs.aColor, gl.UNSIGNED_BYTE, true, this.vertByteSize, 4 * 4);
            // .addAttribute(vertexBuffer, attrs.aTextureId, gl.FLOAT, false, this.vertByteSize, 5 * 4);//用下面的判断，因为MAX_TEXTURES为1的话attrs.aTextureId就不存在了
            if (attrs.aTextureId) {
                vao.addAttribute(vertexBuffer, attrs.aTextureId, gl.FLOAT, false, this.vertByteSize, 5 * 4);
            }
            this.vaos[i] = vao;
        }
    };
    /**
     * 每帧开始渲染前触发
     */
    BatchRenderer.prototype.onPreRender = function () {
        this.vertexCount = 0;
    };
    /**
     * Renders the sprite object.
     * element必须的属性
     *
     * _texture  里面有.BaseTexture
     * _vertexData
     * _indices
     * _worldAlpha
     * _tintRGB
     * _uvs
     *
     * the sprite to render when using this spritebatch
     */
    BatchRenderer.prototype.render = function (element) {
        if (!element._texture || !element._texture.valid) {
            return;
        }
        if (this.currentSize + (element._vertexData.length / 2) > this.size) {
            this.flush();
        }
        this.elements[this.currentIndex++] = element;
        this.currentSize += element._vertexData.length / 2;
        this.currentIndexSize += element._indices.length;
    };
    /**
     * 获得索引buffer
     * @param size
     */
    BatchRenderer.prototype.getIndexBuffer = function (size) {
        // 12 indices is enough for 2 quads
        var roundedP2 = nextPow2(Math.ceil(size / 12));
        var roundedSizeIndex = log2(roundedP2);
        var roundedSize = roundedP2 * 12;
        // if (this.iBuffers.length <= roundedSizeIndex) {
        //     this.iBuffers.length = roundedSizeIndex + 1;
        // }
        var buffer = this.iBuffers[roundedSizeIndex];
        if (!buffer) {
            this.iBuffers[roundedSizeIndex] = buffer = new Uint16Array(roundedSize);
        }
        return buffer;
    };
    /**
     * 获取相应的顶点数据buffer
     * @param size
     */
    BatchRenderer.prototype.getAttributeBuffer = function (size) {
        // 8 vertices is enough for 2 quads
        var roundedP2 = nextPow2(Math.ceil(size / 8));
        log2(roundedP2);
        var roundedSize = roundedP2 * 8;
        // if (this.aBuffers.length <= roundedSizeIndex) {
        //     this.iBuffers.length = roundedSizeIndex + 1;
        // }
        var buffer = this.aBuffers[roundedSize];
        if (!buffer) {
            this.aBuffers[roundedSize] = buffer = new BatchBuffer(roundedSize * this.vertByteSize);
        }
        return buffer;
    };
    /**
     * Renders the content and empties the current batch.
     *
     */
    BatchRenderer.prototype.flush = function () {
        if (this.currentSize === 0) {
            return;
        }
        var gl = this.renderer.gl;
        var MAX_TEXTURES = this.MAX_TEXTURES;
        var buffer = this.getAttributeBuffer(this.currentSize);
        var indexBuffer = this.getIndexBuffer(this.currentIndexSize);
        var elements = this.elements;
        var groups = this.groups;
        var float32View = buffer.float32View;
        var uint32View = buffer.uint32View;
        var touch = this.renderer.textureGC.count;
        var index = 0;
        var indexCount = 0;
        var nextTexture;
        var currentTexture;
        var groupCount = 1;
        var textureCount = 0;
        var currentGroup = groups[0];
        //先用第一个的混色模式
        var blendMode = premultiplyBlendMode[elements[0]._texture.baseTexture.premultipliedAlpha ? 1 : 0][elements[0]._blendMode];
        currentGroup.textureCount = 0;
        currentGroup.start = 0;
        currentGroup.blend = blendMode;
        TICK++;
        var i;
        for (i = 0; i < this.currentIndex; ++i) {
            // upload the sprite elements...
            // they have all ready been calculated so we just need to push them into the buffer.
            var sprite = elements[i];
            elements[i] = null;
            nextTexture = sprite._texture.baseTexture;
            var spriteBlendMode = premultiplyBlendMode[nextTexture.premultipliedAlpha ? 1 : 0][sprite._blendMode];
            if (blendMode !== spriteBlendMode) {
                blendMode = spriteBlendMode;
                // force the batch to break!
                currentTexture = null;
                textureCount = MAX_TEXTURES;
                TICK++;
            }
            if (currentTexture !== nextTexture) {
                currentTexture = nextTexture;
                if (nextTexture._enabledId !== TICK) {
                    if (textureCount === MAX_TEXTURES) {
                        TICK++;
                        textureCount = 0;
                        currentGroup.size = indexCount - currentGroup.start;
                        currentGroup = groups[groupCount++];
                        currentGroup.textureCount = 0;
                        currentGroup.blend = blendMode;
                        currentGroup.start = indexCount;
                    }
                    nextTexture._touchedId = touch;
                    nextTexture._enabledId = TICK;
                    nextTexture._id = textureCount;
                    currentGroup.textures[currentGroup.textureCount++] = nextTexture;
                    textureCount++;
                }
            }
            // argb, nextTexture._id, float32View, uint32View, indexBuffer, index, indexCount);
            this.packGeometry(sprite, float32View, uint32View, indexBuffer, index, indexCount);
            // push a graphics..
            index += (sprite._vertexData.length / 2) * this.vertSize;
            indexCount += sprite._indices.length;
        }
        currentGroup.size = indexCount - currentGroup.start;
        //        this.indexBuffer.update();
        //暂时出现了bug，ios不做特殊处理先，以后有时间排查，暂时应该影响不大
        //貌似没问题了（20210601），但是感觉性能差别不大，先不加了，到时要加的话，也要打开start方法里的注释
        if (getOsType() == "ios" && false) {
            //可能有一帧，在多个地方执行flush
            // this is still needed for IOS performance..
            // it really does not like uploading to the same buffer in a single frame!
            if (this.vaoMax <= this.vertexCount) {
                this.vaoMax++;
                var attrs = this.shader.attributes;
                /* eslint-disable max-len */
                var vertexBuffer = this.vertexBuffers[this.vertexCount] = GLBuffer.createVertexBuffer(gl, null, gl.STREAM_DRAW);
                var indexBufferAdd = this.indexBuffers[this.vertexCount] = GLBuffer.createIndexBuffer(gl, null, gl.STREAM_DRAW);
                // build the vao object that will render..
                var vao = this.renderer.createVao()
                    .addIndex(indexBufferAdd)
                    .addAttribute(vertexBuffer, attrs.aVertexPosition, gl.FLOAT, false, this.vertByteSize, 0)
                    .addAttribute(vertexBuffer, attrs.aTextureCoord, gl.FLOAT, true, this.vertByteSize, 2 * 4)
                    .addAttribute(vertexBuffer, attrs.aColor, gl.UNSIGNED_BYTE, true, this.vertByteSize, 4 * 4);
                // .addAttribute(vertexBuffer, attrs.aTextureId, gl.FLOAT, false, this.vertByteSize, 5 * 4);//理由同上
                if (attrs.aTextureId) {
                    vao.addAttribute(vertexBuffer, attrs.aTextureId, gl.FLOAT, false, this.vertByteSize, 5 * 4);
                }
                this.vaos[this.vertexCount] = vao;
                // console.log(this.vertexCount)
            }
            this.renderer.bindVao(this.vaos[this.vertexCount]);
            this.vertexBuffers[this.vertexCount].upload(buffer.vertices, 0, false);
            this.indexBuffers[this.vertexCount].upload(indexBuffer, 0, false);
            this.vertexCount++;
        }
        else {
            // lets use the faster option, always use buffer number 0
            this.vertexBuffers[this.vertexCount].upload(buffer.vertices, 0, true);
            this.indexBuffers[this.vertexCount].upload(indexBuffer, 0, true);
        }
        //   this.renderer.state.set(this.state);
        var textureManager = this.renderer.textureManager;
        // const stateSystem = this.renderer.state;
        // e.log(groupCount);
        // / render the groups..
        for (i = 0; i < groupCount; i++) {
            var group = groups[i];
            var groupTextureCount = group.textureCount;
            for (var j = 0; j < groupTextureCount; j++) {
                if (group.textures[j] != textureManager.boundTextures[j]) {
                    //location已经和sampleId固定了，就算原先boundsTextures有，也要重新绑定位置
                    // console.log("bindTexture")
                    textureManager.bindTexture(group.textures[j], j, true);
                }
                group.textures[j] = null;
            }
            //混色模式暂不用
            // this.state.blendMode = group.blend;
            // this.state.blend = true;
            // this.renderer.state.setState(this.state);
            // set the blend mode..
            // stateSystem.setBlendMode(group.blend);
            this.renderer.setBlendMode(group.blend);
            gl.drawElements(group.type, group.size, gl.UNSIGNED_SHORT, group.start * 2);
        }
        // reset elements for the next flush
        this.currentIndex = 0;
        this.currentSize = 0;
        this.currentIndexSize = 0;
    };
    BatchRenderer.prototype.packGeometry = function (element, float32View, uint32View, indexBuffer, index, indexCount) {
        var p = index / this.vertSize; // float32View.length / 6 / 2;
        var uvs = element._uvs;
        var indicies = element._indices; // geometry.getIndex().data;// indicies;
        var vertexData = element._vertexData;
        var textureId = element._texture.baseTexture["_id"];
        var _tintRGB = element._tintRGB == undefined ? 16777215 : element._tintRGB;
        var alpha = Math.min(element._worldAlpha, 1.0);
        // we dont call extra function if alpha is 1.0, that's faster
        var argb = alpha < 1.0 && element._texture.baseTexture.premultipliedAlpha ? premultiplyTint(_tintRGB, alpha)
            : _tintRGB + (alpha * 255 << 24);
        // lets not worry about tint! for now..
        for (var i = 0; i < vertexData.length; i += 2) {
            float32View[index++] = vertexData[i];
            float32View[index++] = vertexData[i + 1];
            float32View[index++] = uvs[i];
            float32View[index++] = uvs[i + 1];
            uint32View[index++] = argb;
            float32View[index++] = textureId;
        }
        for (var i = 0; i < indicies.length; i++) {
            indexBuffer[indexCount++] = p + indicies[i];
        }
    };
    /**
     * Starts a new sprite batch.
     */
    BatchRenderer.prototype.start = function () {
        //暂时不考虑2d专门的状态机属性
        // this.renderer.state.setState(this.state);
        this.renderer.bindShader(this.shader);
        // if (getOsType() != "ios") {//暂时出现了bug，ios不做特殊处理先
        this.renderer.bindVao(this.vaos[this.vertexCount]);
        this.vertexBuffers[this.vertexCount].bind();
        this.indexBuffers[this.vertexCount].bind();
        // }
    };
    /**
     * Stops and flushes the current batch.
     *
     */
    BatchRenderer.prototype.stop = function () {
        this.flush();
    };
    /**
     * Destroys the SpriteRenderer.
     *
     */
    BatchRenderer.prototype.destroy = function () {
        for (var i = 0; i < this.vaoMax; i++) {
            // if (this.vertexBuffers[i])
            // {
            //     this.vertexBuffers[i].destroy();
            // }
            if (this.vaos[i]) {
                this.vaos[i].destroy();
            }
        }
        this.renderer.removeEventListener('onPreRender', this.onPreRender, this);
        if (this.shader) {
            this.shader.destroy();
            this.shader = null;
        }
        this.vaos = null;
        _super.prototype.destroy.call(this);
    };
    return BatchRenderer;
}(ObjectRenderer));

/**
 * 渲染器抽象类，用于canvas和webgl
 */
var SystemRenderer = /** @class */ (function (_super) {
    __extends(SystemRenderer, _super);
    function SystemRenderer() {
        var _this = _super.call(this) || this;
        _this.transparent = true;
        _this._backgroundColor = 0x000000;
        _this._backgroundColorRgba = [0, 0, 0, 0];
        _this._backgroundColorString = '#000000';
        _this.backgroundColor = _this._backgroundColor; // run bg color setter
        _this._tempDisplayObjectParent = new Container();
        _this._lastObjectRendered = _this._tempDisplayObjectParent;
        return _this;
    }
    /**
     * 尺寸重置，暂时根据屏幕分辨率
     * @param {number} screenWidth
     * @param {number} screenHeight
     */
    SystemRenderer.prototype.resize = function (width, height) {
        this.width = width;
        this.height = height;
        //下面的不适用了
        // this.htmlElement.width = width * devicePixelRatio;
        // this.htmlElement.height = height * devicePixelRatio;
        // this.htmlElement.style.width = `${width}px`;
        // this.htmlElement.style.height = `${height}px`;
    };
    /**
     * 核心渲染方法，子级重写
     */
    SystemRenderer.prototype.render = function (displayObject, renderTexture, transform) {
    };
    /**
     * 销毁方法
     */
    SystemRenderer.prototype.destroy = function () {
        this.type = RENDERER_TYPE.UNKNOWN;
        this.transparent = false;
        this._backgroundColor = 0;
        this._backgroundColorRgba = null;
        this._backgroundColorString = null;
        this._tempDisplayObjectParent = null;
        this._lastObjectRendered = null;
    };
    Object.defineProperty(SystemRenderer.prototype, "backgroundColor", {
        /**
         * 背景色，十六进制颜色
         * @member {number}
         */
        get: function () {
            return this._backgroundColor;
        },
        /**
         * 背景色，十六进制颜色
         */
        set: function (value) {
            if (this._backgroundColor === value)
                return;
            this._backgroundColor = value;
            this._backgroundColorString = hex2string(value);
            hex2rgb$1(value, this._backgroundColorRgba);
        },
        enumerable: false,
        configurable: true
    });
    return SystemRenderer;
}(EventDispatcher));

var RenderTarget = /** @class */ (function () {
    /**
     * @param {WebGLRenderingContext} gl - The current WebGL drawing context
     * @param {number} [width=0] - the horizontal range of the filter
     * @param {number} [height=0] - the vertical range of the filter
     * @param {number} [scaleMode=SCALE_MODES.LINEAR] - See {@link SCALE_MODES} for possible values
     * @param {boolean} [root=false] - Whether this object is the root element or not
     */
    function RenderTarget(gl, width, height, scaleMode, root) {
        if (width === void 0) { width = 0; }
        if (height === void 0) { height = 0; }
        if (scaleMode === void 0) { scaleMode = SCALE_MODES.LINEAR; }
        if (root === void 0) { root = false; }
        this.gl = gl;
        // next time to create a frame buffer and texture
        this.frameBuffer = null;
        this.texture = null;
        this.clearColor = [0, 0, 0, 0];
        this.size = new Rectangle(0, 0, 1, 1);
        this.projectionMatrix = new Matrix();
        this.transform = null;
        this.frame = null;
        this.defaultFrame = new Rectangle();
        this.destinationFrame = null;
        this.sourceFrame = null;
        this.stencilBuffer = null;
        this.stencilMaskStack = [];
        this.filterData = null;
        this.filterPoolKey = '';
        this.scaleMode = scaleMode;
        this.root = root;
        if (!this.root) {
            this.frameBuffer = GLFramebuffer.createRGBA(gl, 100, 100);
            if (this.scaleMode === SCALE_MODES.NEAREST) {
                this.frameBuffer.texture.enableNearestScaling();
            }
            else {
                this.frameBuffer.texture.enableLinearScaling();
            }
            /*
                A frame buffer needs a target to render to..
                create a texture and bind it attach it to the framebuffer..
             */
            // this is used by the base texture
            this.texture = this.frameBuffer.texture;
        }
        else {
            // make it a null framebuffer..
            this.frameBuffer = new GLFramebuffer(gl, 100, 100);
            //帧缓存为空，gltexture也是空
            this.frameBuffer.framebuffer = null;
        }
        this.setFrame();
        this.resize(width, height);
    }
    /**
     * Clears the filter texture.
     *
     * @param {number[]} [clearColor=this.clearColor] - Array of [r,g,b,a] to clear the framebuffer
     */
    RenderTarget.prototype.clear = function (clearColor) {
        var cc = clearColor || this.clearColor;
        //帧缓存清空，this.frameBuffer.framebuffer为null时，直接清root
        this.frameBuffer.clear(cc[0], cc[1], cc[2], cc[3]); // r,g,b,a);
    };
    /**
     * Binds the stencil buffer.
     *
     */
    RenderTarget.prototype.attachStencilBuffer = function () {
        // TODO check if stencil is done?
        /**
         * The stencil buffer is used for masking in
         * lets create one and then add attach it to the framebuffer..
         */
        if (!this.root) {
            this.frameBuffer.enableStencil();
        }
        //为什么不需要把源数据赋值到this.stencilMaskStack
    };
    /**
     * Sets the frame of the render target.
     *
     * @param {Rectangle} destinationFrame - The destination frame.
     * @param {Rectangle} sourceFrame - The source frame.
     */
    RenderTarget.prototype.setFrame = function (destinationFrame, sourceFrame) {
        this.destinationFrame = destinationFrame || this.destinationFrame || this.defaultFrame;
        this.sourceFrame = sourceFrame || this.sourceFrame || this.destinationFrame;
    };
    /**
     * Binds the buffers and initialises the viewport.
     *
     */
    RenderTarget.prototype.activate = function () {
        // TOOD refactor usage of frame..
        var gl = this.gl;
        // make sure the texture is unbound!
        this.frameBuffer.bind();
        this.calculateProjection(this.destinationFrame, this.sourceFrame);
        if (this.transform) {
            this.projectionMatrix.append(this.transform);
        }
        // TODO add a check as them may be the same!
        if (this.destinationFrame !== this.sourceFrame) {
            gl.enable(gl.SCISSOR_TEST);
            gl.scissor(this.destinationFrame.x | 0, this.destinationFrame.y | 0, this.destinationFrame.width | 0, this.destinationFrame.height | 0);
        }
        else {
            gl.disable(gl.SCISSOR_TEST);
        }
        // TODO - does not need to be updated all the time??
        gl.viewport(this.destinationFrame.x | 0, this.destinationFrame.y | 0, this.destinationFrame.width | 0, this.destinationFrame.height | 0);
    };
    /**
     * Updates the projection matrix based on a projection frame (which is a rectangle)
     *
     * @param {Rectangle} destinationFrame - The destination frame.
     * @param {Rectangle} sourceFrame - The source frame.
     */
    RenderTarget.prototype.calculateProjection = function (destinationFrame, sourceFrame) {
        var pm = this.projectionMatrix;
        // console.log(destinationFrame)
        sourceFrame = sourceFrame || destinationFrame;
        pm.identity();
        // TODO: make dest scale source
        if (!this.root) {
            pm.a = 1 / destinationFrame.width * 2;
            pm.d = 1 / destinationFrame.height * 2;
            pm.tx = -1 - (sourceFrame.x * pm.a);
            pm.ty = -1 - (sourceFrame.y * pm.d);
        }
        else {
            pm.a = 1 / destinationFrame.width * 2;
            pm.d = -1 / destinationFrame.height * 2;
            pm.tx = -1 - (sourceFrame.x * pm.a);
            pm.ty = 1 - (sourceFrame.y * pm.d);
        }
    };
    /**
     * Resizes the texture to the specified width and height
     *
     * @param {number} width - the new width of the texture
     * @param {number} height - the new height of the texture
     */
    RenderTarget.prototype.resize = function (width, height) {
        width = width | 0;
        height = height | 0;
        if (this.size.width === width && this.size.height === height) {
            return;
        }
        this.size.width = width;
        this.size.height = height;
        this.defaultFrame.width = width;
        this.defaultFrame.height = height;
        this.frameBuffer.resize(width, height);
        var projectionFrame = this.frame || this.size;
        this.calculateProjection(projectionFrame);
    };
    /**
     * 销毁方法
     */
    RenderTarget.prototype.destroy = function () {
        this.frameBuffer.destroy();
        this.frameBuffer = null;
        this.texture = null;
    };
    return RenderTarget;
}());

/**
 * Helper class to create a webGL Texture
 *
 */
var TextureManager = /** @class */ (function () {
    /**
     * @param {WebGLRenderer} renderer - A reference to the current renderer
     */
    function TextureManager(renderer) {
        this._nextTextureLocation = 0;
        this.renderer = renderer;
        this.gl = renderer.gl;
        this._managedTextures = [];
        this.renderer.addEventListener('onContextChange', this.onContextChange, this);
    }
    TextureManager.prototype.onContextChange = function () {
        var gl = this.gl;
        var maxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
        this.boundTextures = new Array(maxTextures);
        this.emptyTextures = new Array(maxTextures);
        // now lets fill up the textures with empty ones!
        var emptyGLTexture = GLTexture.fromData(gl, null, 1, 1);
        var tempObj = { _glTextures: {} };
        tempObj._glTextures[this.renderer.CONTEXT_UID] = {};
        for (var i = 0; i < maxTextures; i++) {
            var empty = new BaseTexture();
            empty._glTextures[this.renderer.CONTEXT_UID] = emptyGLTexture;
            this.boundTextures[i] = tempObj;
            this.emptyTextures[i] = empty;
            this.bindTexture(null, i);
        }
    };
    /**
     * Binds the texture. This will return the location of the bound texture.
     * It may not be the same as the one you pass in. This is due to optimisation that prevents
     * needless binding of textures. For example if the texture is already bound it will return the
     * current location of the texture instead of the one provided. To bypass this use force location
     *
     * @param {Texture} texture - the new texture
     * @param {number} location - the suggested texture location
     * @param {boolean} forceLocation - force the location
     * @return {number} bound texture location
     */
    TextureManager.prototype.bindTexture = function (texture, location, forceLocation) {
        texture = texture || this.emptyTextures[location];
        texture = texture.baseTexture || texture;
        texture._touchedId = this.renderer.textureGC.count;
        //从原先绑定过的纹理里找
        if (!forceLocation) {
            // TODO - maybe look into adding boundIds.. save us the loop?
            for (var i = 0; i < this.boundTextures.length; i++) {
                if (this.boundTextures[i] === texture) {
                    return i;
                }
            }
            if (location === undefined) {
                this._nextTextureLocation++;
                this._nextTextureLocation %= this.boundTextures.length;
                location = this.boundTextures.length - this._nextTextureLocation - 1;
            }
        }
        else {
            location = location || 0;
        }
        var gl = this.gl;
        var glTexture = texture._glTextures[this.renderer.CONTEXT_UID];
        //考虑到时用dirty更新的方法，不然有些属性更新可能无效，mipmap等
        if (!glTexture) {
            // this will also bind the texture..
            this.updateTexture(texture, location);
        }
        else {
            // bind the current texture
            if (this.currentLocation !== location) {
                this.currentLocation = location;
                gl.activeTexture(gl.TEXTURE0 + location);
            }
            if (this.boundTextures[location] !== texture) {
                gl.bindTexture(gl.TEXTURE_2D, glTexture.texture);
            }
            this.boundTextures[location] = texture;
        }
        return location;
    };
    /**
     * Gets a texture.
     *
     */
    TextureManager.prototype.getTexture = function () {
        // empty
    };
    /**
     * Updates and/or Creates a WebGL texture for the renderer's context.
     *
     * @param {BaseTexture|Texture} texture - the texture to update
     * @param {number} location - the location the texture will be bound to.
     * @return {GLTexture} The gl texture.
     */
    TextureManager.prototype.updateTexture = function (texture, location) {
        //如果是事件返回的
        if (texture.instanceType === "Event") {
            //选择它的target
            texture = texture.target.baseTexture || texture.target;
        }
        else {
            texture = texture.baseTexture || texture;
        }
        var gl = this.gl;
        var isRenderTexture = !!texture["_glRenderTargets"];
        if (!texture.hasLoaded) {
            return null;
        }
        var boundTextures = this.boundTextures;
        // if the location is undefined then this may have been called by n event.
        // this being the case the texture may already be bound to a slot. As a texture can only be bound once
        // we need to find its current location if it exists.
        if (location === undefined) {
            location = 0;
            // TODO maybe we can use texture bound ids later on...
            // check if texture is already bound..
            for (var i = 0; i < boundTextures.length; ++i) {
                if (boundTextures[i] === texture) {
                    location = i;
                    break;
                }
            }
        }
        boundTextures[location] = texture;
        if (this.currentLocation !== location) {
            this.currentLocation = location;
            gl.activeTexture(gl.TEXTURE0 + location);
        }
        var glTexture = texture._glTextures[this.renderer.CONTEXT_UID];
        if (!glTexture) {
            if (isRenderTexture) {
                var renderTarget = new RenderTarget(this.gl, texture.width, texture.height, texture.scaleMode, false);
                renderTarget.resize(texture.width, texture.height);
                texture._glRenderTargets[this.renderer.CONTEXT_UID] = renderTarget;
                glTexture = renderTarget.texture;
            }
            else {
                glTexture = new GLTexture(this.gl, null, null, null, null);
                //之前已经active过了，upload里也有bind，这里也许不用执行
                // glTexture.bind(location);
                glTexture.premultiplyAlpha = texture.premultipliedAlpha;
                if (texture.source._data) { //是data形式
                    glTexture.uploadData(texture.source._data, texture.width, texture.height);
                }
                else {
                    glTexture.upload(texture.source);
                }
            }
            texture._glTextures[this.renderer.CONTEXT_UID] = glTexture;
            texture.addEventListener('update', this.updateTexture, this);
            texture.addEventListener('dispose', this.destroyTexture, this);
            this._managedTextures.push(texture);
            if (texture.isPowerOfTwo) {
                if (texture.mipmap) {
                    glTexture.enableMipmap();
                }
                if (texture.wrapMode === WRAP_MODES.CLAMP) {
                    glTexture.enableWrapClamp();
                }
                else if (texture.wrapMode === WRAP_MODES.REPEAT) {
                    glTexture.enableWrapRepeat();
                }
                else {
                    glTexture.enableWrapMirrorRepeat();
                }
            }
            else {
                glTexture.enableWrapClamp();
            }
            if (texture.scaleMode === SCALE_MODES.NEAREST) {
                glTexture.enableNearestScaling();
            }
            else {
                glTexture.enableLinearScaling();
            }
        }
        // the texture already exists so we only need to update it..
        else if (isRenderTexture) {
            texture._glRenderTargets[this.renderer.CONTEXT_UID].resize(texture.width, texture.height);
        }
        else {
            if (texture.source._data) { //是data形式
                glTexture.uploadData(texture.source._data, texture.width, texture.height);
            }
            else {
                glTexture.upload(texture.source);
            }
        }
        return glTexture;
    };
    /**
     * unbinds the texture ...
     *
     * @param {Texture} texture - the texture to unbind
     */
    TextureManager.prototype.unbindTexture = function (texture) {
        var gl = this.gl;
        texture = texture.baseTexture || texture;
        for (var i = 0; i < this.boundTextures.length; i++) {
            if (this.boundTextures[i] === texture) {
                this.boundTextures[i] = this.emptyTextures[i];
                if (this.currentLocation !== i) {
                    gl.activeTexture(gl.TEXTURE0 + i);
                    this.currentLocation = i;
                }
                gl.bindTexture(gl.TEXTURE_2D, this.emptyTextures[i]._glTextures[this.renderer.CONTEXT_UID].texture);
            }
        }
    };
    /**
     * Deletes the texture from WebGL
     *
     * @param {BaseTexture|Texture} texture - the texture to destroy
     * @param {boolean} [skipRemove=false] - Whether to skip removing the texture from the TextureManager.
     */
    TextureManager.prototype.destroyTexture = function (texture, skipRemove) {
        //如果是事件返回的
        if (texture.instanceType === "Event") {
            //选择它的target
            texture = texture.target;
        }
        texture = texture.baseTexture || texture;
        if (!texture.hasLoaded) {
            return;
        }
        var uid = this.renderer.CONTEXT_UID;
        var glTextures = texture._glTextures;
        var glRenderTargets = texture._glRenderTargets;
        if (glTextures[uid]) {
            this.unbindTexture(texture);
            glTextures[uid].destroy();
            texture.removeEventListener('update', this.updateTexture, this);
            texture.removeEventListener('dispose', this.destroyTexture, this);
            delete glTextures[uid];
            if (!skipRemove) {
                var i = this._managedTextures.indexOf(texture);
                if (i !== -1) {
                    removeItems(this._managedTextures, i, 1);
                }
            }
        }
        if (glRenderTargets && glRenderTargets[uid]) {
            glRenderTargets[uid].destroy();
            delete glRenderTargets[uid];
        }
    };
    /**
     * Deletes all the textures from WebGL
     */
    TextureManager.prototype.removeAll = function () {
        // empty all the old gl textures as they are useless now
        for (var i = 0; i < this._managedTextures.length; ++i) {
            var texture = this._managedTextures[i];
            if (texture._glTextures[this.renderer.CONTEXT_UID]) {
                delete texture._glTextures[this.renderer.CONTEXT_UID];
            }
        }
    };
    /**
     * Destroys this manager and removes all its textures
     */
    TextureManager.prototype.destroy = function () {
        // destroy managed textures
        for (var i = 0; i < this._managedTextures.length; ++i) {
            var texture = this._managedTextures[i];
            this.destroyTexture(texture, true);
            //上面已经移除了
            // texture.removeEventListener('update', this.updateTexture, this);
            // texture.removeEventListener('dispose', this.destroyTexture, this);
        }
        //移除绑定事件
        this.renderer.removeEventListener('onContextChange', this.onContextChange, this);
        this.renderer = null;
        this._managedTextures = null;
    };
    return TextureManager;
}());

/**
 * TextureGarbageCollector. This class manages the GPU and ensures that it does not get clogged
 * up with textures that are no longer being used.
 *
 */
var TextureGarbageCollector = /** @class */ (function () {
    /**
     * @param {WebGLRenderer} renderer - The renderer this manager works for.
     */
    function TextureGarbageCollector(renderer) {
        this.renderer = renderer;
        this.count = 0;
        this.checkCount = 0;
        this.maxIdle = 60 * 60;
        this.checkCountMax = 60 * 10;
        this.mode = GC_MODES.AUTO;
    }
    /**
     * Checks to see when the last time a texture was used
     * if the texture has not been used for a specified amount of time it will be removed from the GPU
     */
    TextureGarbageCollector.prototype.update = function () {
        this.count++;
        if (this.mode === GC_MODES.MANUAL) {
            return;
        }
        this.checkCount++;
        if (this.checkCount > this.checkCountMax) {
            this.checkCount = 0;
            this.run();
        }
    };
    /**
     * Checks to see when the last time a texture was used
     * if the texture has not been used for a specified amount of time it will be removed from the GPU
     */
    TextureGarbageCollector.prototype.run = function () {
        var tm = this.renderer.textureManager;
        var managedTextures = tm._managedTextures;
        var wasRemoved = false;
        for (var i = 0; i < managedTextures.length; i++) {
            var texture = managedTextures[i];
            // only supports non generated textures at the moment!
            //去掉长期不用的纹理
            if (!texture._glRenderTargets && this.count - texture._touchedId > this.maxIdle) {
                tm.destroyTexture(texture, true);
                managedTextures[i] = null;
                wasRemoved = true;
            }
        }
        if (wasRemoved) {
            var j = 0;
            for (var i = 0; i < managedTextures.length; i++) {
                if (managedTextures[i] !== null) {
                    managedTextures[j++] = managedTextures[i];
                }
            }
            managedTextures.length = j;
        }
    };
    /**
     * Removes all the textures within the specified displayObject and its children from the GPU
     *
     * @param {DisplayObject} displayObject - the displayObject to remove the textures from.
     */
    TextureGarbageCollector.prototype.unload = function (displayObject) {
        var tm = this.renderer.textureManager;
        // only destroy non generated textures
        if (displayObject._texture && displayObject._texture._glRenderTargets) {
            tm.destroyTexture(displayObject._texture, true);
        }
        for (var i = displayObject.children.length - 1; i >= 0; i--) {
            this.unload(displayObject.children[i]);
        }
    };
    return TextureGarbageCollector;
}());

/**
 * Maps gl blend combinations to WebGL.
 * @function mapWebGLBlendModes
 * @private
 * @param {WebGLRenderingContext} gl - The rendering context.
 * @param {string[]} [array=[]] - The array to output into.
 * @return {string[]} Mapped modes.
 */
function mapWebGLBlendModes(gl, array) {
    if (array === void 0) { array = []; }
    // TODO - premultiply alpha would be different.
    // add a boolean for that!
    array[BLEND_MODES.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
    // array[BLEND_MODES.ADD] = [gl.ONE, gl.DST_ALPHA];
    // array[BLEND_MODES.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA];
    // array[BLEND_MODES.SCREEN] = [gl.ONE, gl.ONE_MINUS_SRC_COLOR];
    //下面修改5.0上的，用新的stateManager
    array[BLEND_MODES.ADD] = [gl.ONE, gl.DST_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
    array[BLEND_MODES.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
    array[BLEND_MODES.SCREEN] = [gl.ONE, gl.ONE_MINUS_SRC_COLOR, gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
    array[BLEND_MODES.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
    array[BLEND_MODES.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
    array[BLEND_MODES.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
    array[BLEND_MODES.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
    array[BLEND_MODES.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
    array[BLEND_MODES.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
    array[BLEND_MODES.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
    array[BLEND_MODES.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
    array[BLEND_MODES.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
    array[BLEND_MODES.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
    array[BLEND_MODES.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
    array[BLEND_MODES.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
    array[BLEND_MODES.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
    array[BLEND_MODES.NONE] = [0, 0];
    // not-premultiplied blend modes
    array[BLEND_MODES.NORMAL_NPM] = [gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
    array[BLEND_MODES.ADD_NPM] = [gl.SRC_ALPHA, gl.DST_ALPHA, gl.ONE, gl.DST_ALPHA];
    array[BLEND_MODES.SCREEN_NPM] = [gl.SRC_ALPHA, gl.ONE_MINUS_SRC_COLOR, gl.ONE, gl.ONE_MINUS_SRC_COLOR];
    //和NORMAL一致
    array[BLEND_MODES.SRC_OVER] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
    // composite operations
    array[BLEND_MODES.SRC_IN] = [gl.DST_ALPHA, gl.ZERO];
    array[BLEND_MODES.SRC_OUT] = [gl.ONE_MINUS_DST_ALPHA, gl.ZERO];
    array[BLEND_MODES.SRC_ATOP] = [gl.DST_ALPHA, gl.ONE_MINUS_SRC_ALPHA];
    array[BLEND_MODES.DST_OVER] = [gl.ONE_MINUS_DST_ALPHA, gl.ONE];
    array[BLEND_MODES.DST_IN] = [gl.ZERO, gl.SRC_ALPHA];
    array[BLEND_MODES.DST_OUT] = [gl.ZERO, gl.ONE_MINUS_SRC_ALPHA];
    array[BLEND_MODES.DST_ATOP] = [gl.ONE_MINUS_DST_ALPHA, gl.SRC_ALPHA];
    //擦除效果,无效，到时查下，是否因为alpha色值合并了
    array[BLEND_MODES.ERASE] = [gl.ZERO, gl.ONE, gl.SRC_ALPHA, 0];
    // SUBTRACT from flash
    array[BLEND_MODES.SUBTRACT] = [gl.ONE, gl.ONE, gl.ONE, gl.ONE, gl.FUNC_REVERSE_SUBTRACT, gl.FUNC_ADD];
    return array;
}

var BLEND = 0;
var DEPTH_TEST = 1;
var FRONT_FACE = 2;
var CULL_FACE = 3;
var BLEND_FUNC = 4;
/**
 * A WebGL state machines
 * 状态机管理类
 * @class
 */
var WebGLState = /** @class */ (function () {
    /**
     * @param {WebGLRenderingContext} gl - The current WebGL rendering context
     */
    function WebGLState(gl) {
        this.activeState = new Uint8Array(16);
        this.defaultState = new Uint8Array(16);
        // default blend mode..暂时不用混色
        this.defaultState[0] = 1;
        this.gl = gl;
        this.maxAttribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
        this.attribState = {
            tempAttribState: new Array(this.maxAttribs),
            attribState: new Array(this.maxAttribs),
        };
        this.blendModes = mapWebGLBlendModes(gl);
        // check we have vao..
        this.nativeVaoExtension = (gl.getExtension('OES_vertex_array_object')
            || gl.getExtension('MOZ_OES_vertex_array_object')
            || gl.getExtension('WEBKIT_OES_vertex_array_object'));
    }
    /**
     * Sets the current state
     *
     * @param {*} state - The state to set.
     */
    WebGLState.prototype.setState = function (state) {
        this.setBlend(state[BLEND]);
        this.setDepthTest(state[DEPTH_TEST]);
        this.setFrontFace(state[FRONT_FACE]);
        this.setCullFace(state[CULL_FACE]);
        this.setBlendMode(state[BLEND_FUNC]);
    };
    /**
     * Enables or disabled blending.
     *
     * @param {boolean} value - Turn on or off webgl blending.
     */
    WebGLState.prototype.setBlend = function (value) {
        value = value ? 1 : 0;
        if (this.activeState[BLEND] === value) {
            return;
        }
        this.activeState[BLEND] = value;
        this.gl[value ? 'enable' : 'disable'](this.gl.BLEND);
    };
    /**
     * Sets the blend mode.
     *
     * @param {number} value - The blend mode to set to.
     */
    WebGLState.prototype.setBlendMode = function (value) {
        if (value === this.activeState[BLEND_FUNC]) {
            return;
        }
        this.activeState[BLEND_FUNC] = value;
        var mode = this.blendModes[value];
        if (mode.length === 2) {
            this.gl.blendFunc(mode[0], mode[1]);
        }
        else {
            this.gl.blendFuncSeparate(mode[0], mode[1], mode[2], mode[3]);
        }
    };
    /**
     * Sets whether to enable or disable depth test.
     *
     * @param {boolean} value - Turn on or off webgl depth testing.
     */
    WebGLState.prototype.setDepthTest = function (value) {
        value = value ? 1 : 0;
        if (this.activeState[DEPTH_TEST] === value) {
            return;
        }
        this.activeState[DEPTH_TEST] = value;
        this.gl[value ? 'enable' : 'disable'](this.gl.DEPTH_TEST);
    };
    /**
     * 设置是否开启剔除功能
     * @param {boolean} value - Turn on or off webgl cull face.
     */
    WebGLState.prototype.setCullFace = function (value) {
        value = value ? 1 : 0;
        if (this.activeState[CULL_FACE] === value) {
            return;
        }
        this.activeState[CULL_FACE] = value;
        this.gl[value ? 'enable' : 'disable'](this.gl.CULL_FACE);
    };
    /**
     * 设置剔除的面，基本不设置，因为设置正方面就行setFrontFace
     * gl.FRONT
     * gl.BACK 默认
     * gl.FRONT_AND_BACK
     */
    // setCullSide(value){
    //     value = value ? 1 : 0;
    // }
    /**
     * 设置gl的正面的绘制顺序，
     * @param {boolean} value - true是顺时针，false是逆时针
     */
    WebGLState.prototype.setFrontFace = function (value) {
        value = value ? 1 : 0;
        if (this.activeState[FRONT_FACE] === value) {
            return;
        }
        this.activeState[FRONT_FACE] = value;
        this.gl.frontFace(this.gl[value ? 'CW' : 'CCW']);
    };
    /**
     * Disables all the vaos in use
     *
     */
    WebGLState.prototype.resetAttributes = function () {
        for (var i = 0; i < this.attribState.tempAttribState.length; i++) {
            this.attribState.tempAttribState[i] = 0;
        }
        for (var i = 0; i < this.attribState.attribState.length; i++) {
            this.attribState.attribState[i] = 0;
        }
        // im going to assume one is always active for performance reasons.
        for (var i = 1; i < this.maxAttribs; i++) {
            this.gl.disableVertexAttribArray(i);
        }
    };
    // used
    /**
     * Resets all the logic and disables the vaos
     */
    WebGLState.prototype.resetToDefault = function () {
        // unbind any VAO if they exist..
        if (this.nativeVaoExtension) {
            this.nativeVaoExtension.bindVertexArrayOES(null);
        }
        // reset all attributes..
        this.resetAttributes();
        // set active state so we can force overrides of gl state
        for (var i = 0; i < this.activeState.length; ++i) {
            this.activeState[i] = 32;
        }
        // 翻转Y纹理，gl状态默认不翻转false
        this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, false);
        this.setState(this.defaultState);
    };
    /**
     *
     */
    WebGLState.prototype.resetTo3D = function () {
        //允许深度检测
        this.setDepthTest(1);
        //设置逆时针为正面
        this.setFrontFace(0);
        //设置剔除
        this.setCullFace(1);
    };
    return WebGLState;
}());

/**
 * 批处理管理器，用于切换渲染插件
 * @class
 */
var BatchManager = /** @class */ (function () {
    function BatchManager(renderer) {
        this.renderer = renderer;
        this.emptyRenderer = new ObjectRenderer(renderer);
        this.currentRenderer = this.emptyRenderer;
    }
    /**
     * Changes the current renderer to the one given in parameter
     *
     * @param {ObjectRenderer} objectRenderer - The object renderer to use.
     */
    BatchManager.prototype.setObjectRenderer = function (objectRenderer) {
        if (this.currentRenderer === objectRenderer) {
            return;
        }
        this.currentRenderer.stop();
        this.currentRenderer = objectRenderer;
        this.currentRenderer.start();
    };
    /**
     * This should be called if you wish to do some custom rendering
     * It will basically render anything that may be batched up such as sprites
     */
    BatchManager.prototype.flush = function () {
        this.setObjectRenderer(this.emptyRenderer);
    };
    /**
     * Reset the system to an empty renderer
     */
    BatchManager.prototype.reset = function () {
        this.setObjectRenderer(this.emptyRenderer);
    };
    return BatchManager;
}());

function extractUniformsFromSrc(vertexSrc, fragmentSrc) {
    var vertUniforms = extractUniformsFromString(vertexSrc);
    var fragUniforms = extractUniformsFromString(fragmentSrc);
    // return Object["assign"](vertUniforms, fragUniforms);
    return __assign(__assign({}, vertUniforms), fragUniforms);
}
function extractUniformsFromString(string) {
    var maskRegex = new RegExp('^(projectionMatrix|uSampler|filterArea|filterClamp)$');
    var uniforms = {};
    var nameSplit;
    // clean the lines a little - remove extra spaces / tabs etc
    // then split along ';'
    var lines = string.replace(/\s+/g, ' ')
        .split(/\s*;\s*/);
    // loop through..
    for (var i = 0; i < lines.length; i++) {
        var line = lines[i].trim();
        if (line.indexOf('uniform') > -1) {
            var splitLine = line.split(' ');
            var type = splitLine[1];
            var name = splitLine[2];
            var size = 1;
            if (name.indexOf('[') > -1) {
                // array!
                nameSplit = name.split(/\[|]/);
                name = nameSplit[0];
                size *= Number(nameSplit[1]);
            }
            if (!name.match(maskRegex)) {
                uniforms[name] = {
                    value: defaultValue(type, size),
                    name: name,
                    type: type,
                };
            }
        }
    }
    return uniforms;
}

var SOURCE_KEY_MAP = {};
/**
 * 基本就是一个着色器，暂时不考虑集成GLShader，还不晓得咋搞
 */
var Filter = /** @class */ (function () {
    /**
     * @param {string} [vertexSrc] - The source of the vertex shader.
     * @param {string} [fragmentSrc] - The source of the fragment shader.
     * @param {object} [uniforms] - Custom uniforms to use to augment the built-in ones.
     */
    function Filter(vertexSrc, fragmentSrc, uniforms) {
        this.vertexSrc = vertexSrc || Filter.defaultVertexSrc;
        this.fragmentSrc = fragmentSrc || Filter.defaultFragmentSrc;
        this._blendMode = BLEND_MODES.NORMAL;
        this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc);
        this.uniforms = {};
        for (var i in this.uniformData) {
            this.uniforms[i] = this.uniformData[i].value;
            if (this.uniformData[i].type) {
                this.uniformData[i].type = this.uniformData[i].type.toLowerCase();
            }
        }
        // this is where we store shader references..
        // TODO we could cache this!
        this.glShaders = {};
        // used for cacheing.. sure there is a better way!
        if (!SOURCE_KEY_MAP[this.vertexSrc + this.fragmentSrc]) {
            SOURCE_KEY_MAP[this.vertexSrc + this.fragmentSrc] = uid();
        }
        this.glShaderKey = SOURCE_KEY_MAP[this.vertexSrc + this.fragmentSrc];
        this.padding = 4;
        this.resolution = 1;
        this.enabled = true;
        this.autoFit = true;
    }
    Object.defineProperty(Filter.prototype, "blendMode", {
        get: function () {
            return this._blendMode;
        },
        /**
         * 别用先
         */
        set: function (value) {
            this._blendMode = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Filter.prototype, "resolution", {
        get: function () {
            return this._resolution;
        },
        set: function (v) {
            this._resolution = v;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * Applies the filter
     *
     * @param {FilterManager} filterManager - The renderer to retrieve the filter from
     * @param {RenderTarget} input - The input render target.
     * @param {RenderTarget} output - The target to output to.
     * @param {boolean} clear - Should the output be cleared before rendering to it
     * @param {object} [currentState] - It's current state of filter.
     *        There are some useful properties in the currentState :
     *        target, filters, sourceFrame, destinationFrame, renderTarget, resolution
     */
    Filter.prototype.apply = function (filterManager, input, output, clear) {
        filterManager.applyFilter(this, input, output, clear);
    };
    Object.defineProperty(Filter, "defaultVertexSrc", {
        /**
         * The default vertex shader source
         *
         * @static
         * @constant
         */
        get: function () {
            return [
                'attribute vec2 aVertexPosition;',
                'attribute vec2 aTextureCoord;',
                'uniform mat3 projectionMatrix;',
                'uniform mat3 filterMatrix;',
                'varying vec2 vTextureCoord;',
                'varying vec2 vFilterCoord;',
                'void main(void){',
                '   gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);',
                '   vFilterCoord = ( filterMatrix * vec3( aTextureCoord, 1.0)  ).xy;',
                '   vTextureCoord = aTextureCoord ;',
                '}',
            ].join('\n');
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Filter, "defaultFragmentSrc", {
        /**
         * The default fragment shader source
         *
         * @static
         * @constant
         */
        get: function () {
            return [
                'varying vec2 vTextureCoord;',
                'varying vec2 vFilterCoord;',
                'uniform sampler2D uSampler;',
                'uniform sampler2D filterSampler;',
                'void main(void){',
                '   vec4 masky = texture2D(filterSampler, vFilterCoord);',
                '   vec4 sample = texture2D(uSampler, vTextureCoord);',
                '   vec4 color;',
                '   if(mod(vFilterCoord.x, 1.0) > 0.5)',
                '   {',
                '     color = vec4(1.0, 0.0, 0.0, 1.0);',
                '   }',
                '   else',
                '   {',
                '     color = vec4(0.0, 1.0, 0.0, 1.0);',
                '   }',
                // '   gl_FragColor = vec4(mod(vFilterCoord.x, 1.5), vFilterCoord.y,0.0,1.0);',
                '   gl_FragColor = mix(sample, masky, 0.5);',
                '   gl_FragColor *= sample.a;',
                '}',
            ].join('\n');
        },
        enumerable: false,
        configurable: true
    });
    return Filter;
}());

var fxaaVert = "precision highp float;" +
    "attribute vec2 aVertexPosition;" +
    "attribute vec2 aTextureCoord;" +
    "uniform mat3 projectionMatrix;" +
    "varying vec2 v_rgbNW;" +
    "varying vec2 v_rgbNE;" +
    "varying vec2 v_rgbSW;" +
    "varying vec2 v_rgbSE;" +
    "varying vec2 v_rgbM;" +
    "uniform vec4 filterArea;" +
    "varying vec2 vTextureCoord;" +
    "vec2 mapCoord( vec2 coord ){" +
    "coord *= filterArea.xy;" +
    "coord += filterArea.zw;" +
    "return coord;" +
    "}" +
    "vec2 unmapCoord( vec2 coord ){" +
    "coord -= filterArea.zw;" +
    "coord /= filterArea.xy;" +
    "return coord;" +
    "}" +
    //到时考虑这里编译能否成功
    "void texcoords(vec2 fragCoord, vec2 resolution," +
    "out vec2 v_rgbNW, out vec2 v_rgbNE," +
    "out vec2 v_rgbSW, out vec2 v_rgbSE," +
    "out vec2 v_rgbM) {" +
    "vec2 inverseVP = 1.0 / resolution.xy;" +
    "v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP;" +
    "v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP;" +
    "v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP;" +
    "v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP;" +
    "v_rgbM = vec2(fragCoord * inverseVP);" +
    "}" +
    "void main(void) {" +
    "gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);" +
    "vTextureCoord = aTextureCoord;" +
    "vec2 fragCoord = vTextureCoord * filterArea.xy;" +
    "texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM);" +
    "}";
var fxaaFrag = [
    'precision highp float;',
    'varying vec2 v_rgbNW;',
    'varying vec2 v_rgbNE;',
    'varying vec2 v_rgbSW;',
    'varying vec2 v_rgbSE;',
    'varying vec2 v_rgbM;',
    'varying vec2 vTextureCoord;',
    'uniform sampler2D uSampler;',
    'uniform vec4 filterArea;',
    '#ifndef FXAA_REDUCE_MIN',
    '#define FXAA_REDUCE_MIN   (1.0/ 128.0)',
    '#endif',
    '#ifndef FXAA_REDUCE_MUL',
    '#define FXAA_REDUCE_MUL   (1.0 / 8.0)',
    '#endif',
    '#ifndef FXAA_SPAN_MAX',
    '#define FXAA_SPAN_MAX     8.0',
    '#endif',
    'vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution,',
    'vec2 v_rgbNW, vec2 v_rgbNE,',
    'vec2 v_rgbSW, vec2 v_rgbSE,',
    'vec2 v_rgbM) {',
    'vec4 color;',
    'mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y);',
    'vec3 rgbNW = texture2D(tex, v_rgbNW).xyz;',
    'vec3 rgbNE = texture2D(tex, v_rgbNE).xyz;',
    'vec3 rgbSW = texture2D(tex, v_rgbSW).xyz;',
    'vec3 rgbSE = texture2D(tex, v_rgbSE).xyz;',
    'vec4 texColor = texture2D(tex, v_rgbM);',
    'vec3 rgbM  = texColor.xyz;',
    'vec3 luma = vec3(0.299, 0.587, 0.114);',
    'float lumaNW = dot(rgbNW, luma);',
    'float lumaNE = dot(rgbNE, luma);',
    'float lumaSW = dot(rgbSW, luma);',
    'float lumaSE = dot(rgbSE, luma);',
    'float lumaM  = dot(rgbM,  luma);',
    'float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));',
    'float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));',
    'mediump vec2 dir;',
    'dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));',
    'dir.y =  ((lumaNW + lumaSW) - (lumaNE + lumaSE));',
    'float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) *',
    '(0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN);',
    'float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);',
    'dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX),',
    'max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),',
    'dir * rcpDirMin)) * inverseVP;',
    'vec3 rgbA = 0.5 * (',
    'texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz +',
    'texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz);',
    'vec3 rgbB = rgbA * 0.5 + 0.25 * (',
    'texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz +',
    'texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz);',
    'float lumaB = dot(rgbB, luma);',
    'if ((lumaB < lumaMin) || (lumaB > lumaMax))',
    'color = vec4(rgbA, texColor.a);',
    'else',
    'color = vec4(rgbB, texColor.a);',
    'return color;',
    '}',
    'void main() {',
    'vec2 fragCoord = vTextureCoord * filterArea.xy;',
    'vec4 color;',
    'color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM);',
    'gl_FragColor = color;',
    '}'
].join("\n");
/**
 *
 * Basic FXAA implementation based on the code on geeks3d.com with the
 * modification that the texture2DLod stuff was removed since it's
 * unsupported by WebGL.
 *
 * @see https://github.com/mitsuhiko/webgl-meincraft
 *
 * @class
 * @extends Filter
 * @memberof filters
 *
 */
var FXAAFilter = /** @class */ (function (_super) {
    __extends(FXAAFilter, _super);
    function FXAAFilter() {
        return _super.call(this, fxaaVert, fxaaFrag) || this;
    }
    return FXAAFilter;
}(Filter));

//默认下顶点着色器都用highp float精度，片元着色器用mediump float
var defaultVert = "precision highp float;" +
    "attribute vec2 aVertexPosition;" +
    "attribute vec2 aTextureCoord;" +
    "uniform mat3 projectionMatrix;" +
    "varying vec2 vTextureCoord;" +
    "void main(void){" +
    "gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);" +
    "vTextureCoord = aTextureCoord;" +
    "}";
var defaultFilterMatrix = "precision highp float;" +
    "attribute vec2 aVertexPosition;" +
    "attribute vec2 aTextureCoord;" +
    "uniform mat3 projectionMatrix;" +
    "uniform mat3 filterMatrix;" +
    "varying vec2 vTextureCoord;" +
    "varying vec2 vFilterCoord;" +
    "void main(void){" +
    "gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);" +
    "vFilterCoord = ( filterMatrix * vec3( aTextureCoord, 1.0)  ).xy;" +
    "vTextureCoord = aTextureCoord;" +
    "}";

var noiseFrag = "precision mediump float;" +
    "varying vec2 vTextureCoord;" +
    "varying vec4 vColor;" +
    "uniform float uNoise;" +
    "uniform float uSeed;" +
    "uniform sampler2D uSampler;" +
    "float rand(vec2 co){" +
    "return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);" +
    "}" +
    "void main(){" +
    "vec4 color = texture2D(uSampler, vTextureCoord);" +
    "float randomValue = rand(gl_FragCoord.xy * uSeed);" +
    "float diff = (randomValue - 0.5) * uNoise;" +
    // Un-premultiply alpha before applying the color matrix. See issue #3539.
    "if (color.a > 0.0) {" +
    "color.rgb /= color.a;" +
    "}" +
    "color.r += diff;" +
    "color.g += diff;" +
    "color.b += diff;" +
    // Premultiply alpha again.
    "color.rgb *= color.a;" +
    "gl_FragColor = color;" +
    "}";
/**
 * @author Vico @vicocotea
 * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/adjust/noise.js
 */
/**
 * A Noise effect filter.
 *
 * @class
 * @extends Filter
 * @memberof filters
 */
var NoiseFilter = /** @class */ (function (_super) {
    __extends(NoiseFilter, _super);
    /**
     * @param {number} noise - The noise intensity, should be a normalized value in the range [0, 1].
     * @param {number} seed - A random seed for the noise generation. Default is `Math.random()`.
     */
    function NoiseFilter(noise, seed) {
        if (noise === void 0) { noise = 0.5; }
        if (seed === void 0) { seed = Math.random(); }
        var _this = _super.call(this, defaultVert, noiseFrag) || this;
        _this.noise = noise;
        _this.seed = seed;
        return _this;
    }
    Object.defineProperty(NoiseFilter.prototype, "noise", {
        /**
         * The amount of noise to apply, this value should be in the range (0, 1].
         *
         * @member {number}
         * @default 0.5
         */
        get: function () {
            return this.uniforms.uNoise;
        },
        set: function (value) {
            this.uniforms.uNoise = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(NoiseFilter.prototype, "seed", {
        /**
         * A seed value to apply to the random noise generation. `Math.random()` is a good value to use.
         *
         * @member {number}
         */
        get: function () {
            return this.uniforms.uSeed;
        },
        set: function (value) {
            this.uniforms.uSeed = value;
        },
        enumerable: false,
        configurable: true
    });
    return NoiseFilter;
}(Filter));

var displacementFrag = 'precision mediump float;' +
    'varying vec2 vFilterCoord;' +
    'varying vec2 vTextureCoord;' +
    'uniform vec2 scale;' +
    'uniform sampler2D uSampler;' +
    'uniform sampler2D mapSampler;' +
    'uniform vec4 filterArea;' +
    'uniform vec4 filterClamp;' +
    'void main(void){' +
    'vec4 map = texture2D(mapSampler, vFilterCoord);' +
    'map -= 0.5;' +
    'map.xy *= scale / filterArea.xy;' +
    'gl_FragColor = texture2D(uSampler, clamp(vec2(vTextureCoord.x + map.x, vTextureCoord.y + map.y), filterClamp.xy, filterClamp.zw));' +
    '}';
/**
 * The DisplacementFilter class uses the pixel values from the specified texture
 * (called the displacement map) to perform a displacement of an object. You can
 * use this filter to apply all manor of crazy warping effects. Currently the r
 * property of the texture is used to offset the x and the g property of the texture
 * is used to offset the y.
 *
 * @class
 * @extends Filter
 * @memberof filters
 */
var DisplacementFilter = /** @class */ (function (_super) {
    __extends(DisplacementFilter, _super);
    /**
     * @param {Sprite} sprite - The sprite used for the displacement map. (make sure its added to the scene!)
     * @param {number} scale - The scale of the displacement
     */
    function DisplacementFilter(sprite, scale) {
        var _this = this;
        var maskMatrix = new Matrix();
        sprite.renderable = false;
        _this = _super.call(this, defaultFilterMatrix, displacementFrag) || this;
        _this.maskSprite = sprite;
        _this.maskMatrix = maskMatrix;
        _this.uniforms.mapSampler = sprite._texture;
        _this.uniforms.filterMatrix = maskMatrix;
        _this.uniforms.scale = { x: 1, y: 1 };
        if (scale === null || scale === undefined)
            scale = 20;
        _this.scale = new Point(scale, scale);
        return _this;
    }
    /**
     * Applies the filter.
     *
     * @param {FilterManager} filterManager - The manager.
     * @param {RenderTarget} input - The input target.
     * @param {RenderTarget} output - The output target.
     */
    DisplacementFilter.prototype.apply = function (filterManager, input, output) {
        this.uniforms.filterMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, this.maskSprite);
        this.uniforms.scale.x = this.scale.x;
        this.uniforms.scale.y = this.scale.y;
        // draw the filter...
        filterManager.applyFilter(this, input, output);
    };
    Object.defineProperty(DisplacementFilter.prototype, "map", {
        /**
         * The texture used for the displacement map. Must be power of 2 sized texture.
         *
         * @member {Texture}
         */
        get: function () {
            return this.uniforms.mapSampler;
        },
        set: function (value) {
            this.uniforms.mapSampler = value;
        },
        enumerable: false,
        configurable: true
    });
    return DisplacementFilter;
}(Filter));

var vertTemplate = [
    'attribute vec2 aVertexPosition;',
    'attribute vec2 aTextureCoord;',
    'uniform float strength;',
    'uniform mat3 projectionMatrix;',
    'varying vec2 vBlurTexCoords[%size%];',
    'void main(void)',
    '{',
    'gl_Position = vec4((projectionMatrix * vec3((aVertexPosition), 1.0)).xy, 0.0, 1.0);',
    '%blur%',
    '}',
].join('\n');
function generateVertBlurSource(kernelSize, x) {
    var halfLength = Math.ceil(kernelSize / 2);
    var vertSource = vertTemplate;
    var blurLoop = '';
    var template;
    // let value;
    if (x) {
        template = 'vBlurTexCoords[%index%] = aTextureCoord + vec2(%sampleIndex% * strength, 0.0);';
    }
    else {
        template = 'vBlurTexCoords[%index%] = aTextureCoord + vec2(0.0, %sampleIndex% * strength);';
    }
    for (var i = 0; i < kernelSize; i++) {
        var blur = template.replace('%index%', i);
        // value = i;
        // if(i >= halfLength)
        // {
        //     value = kernelSize - i - 1;
        // }
        blur = blur.replace('%sampleIndex%', i - (halfLength - 1) + ".0");
        blurLoop += blur;
        blurLoop += '\n';
    }
    vertSource = vertSource.replace('%blur%', blurLoop);
    vertSource = vertSource.replace('%size%', kernelSize);
    return vertSource;
}

var GAUSSIAN_VALUES = {
    5: [0.153388, 0.221461, 0.250301],
    7: [0.071303, 0.131514, 0.189879, 0.214607],
    9: [0.028532, 0.067234, 0.124009, 0.179044, 0.20236],
    11: [0.0093, 0.028002, 0.065984, 0.121703, 0.175713, 0.198596],
    13: [0.002406, 0.009255, 0.027867, 0.065666, 0.121117, 0.174868, 0.197641],
    15: [0.000489, 0.002403, 0.009246, 0.02784, 0.065602, 0.120999, 0.174697, 0.197448],
};
var fragTemplate = [
    'precision mediump float;',
    'varying vec2 vBlurTexCoords[%size%];',
    'uniform sampler2D uSampler;',
    'void main(void)',
    '{',
    '    gl_FragColor = vec4(0.0);',
    '    %blur%',
    '}',
].join('\n');
function generateFragBlurSource(kernelSize) {
    var kernel = GAUSSIAN_VALUES[kernelSize];
    var halfLength = kernel.length;
    var fragSource = fragTemplate;
    var blurLoop = '';
    var template = 'gl_FragColor += texture2D(uSampler, vBlurTexCoords[%index%]) * %value%;';
    var value;
    for (var i = 0; i < kernelSize; i++) {
        var blur = template.replace('%index%', i + "");
        value = i;
        if (i >= halfLength) {
            value = kernelSize - i - 1;
        }
        blur = blur.replace('%value%', kernel[value]);
        blurLoop += blur;
        blurLoop += '\n';
    }
    fragSource = fragSource.replace('%blur%', blurLoop);
    fragSource = fragSource.replace('%size%', kernelSize);
    return fragSource;
}

function getMaxBlurKernelSize(gl) {
    var maxVaryings = (gl.getParameter(gl.MAX_VARYING_VECTORS));
    var kernelSize = 15;
    while (kernelSize > maxVaryings) {
        kernelSize -= 2;
    }
    return kernelSize;
}

/**
 * The BlurXFilter applies a horizontal Gaussian blur to an object.
 *
 * @class
 * @extends Filter
 * @memberof filters
 */
var BlurXFilter = /** @class */ (function (_super) {
    __extends(BlurXFilter, _super);
    /**
     * @param {number} strength - The strength of the blur filter.
     * @param {number} quality - The quality of the blur filter.
     * @param {number} resolution - The resolution of the blur filter.
     * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15.
     */
    function BlurXFilter(strength, quality, resolution, kernelSize) {
        var _this = this;
        kernelSize = kernelSize || 5;
        var vertSrc = generateVertBlurSource(kernelSize, true);
        var fragSrc = generateFragBlurSource(kernelSize);
        _this = _super.call(this, 
        // vertex shader
        vertSrc, 
        // fragment shader
        fragSrc) || this;
        _this.resolution = resolution || 1;
        _this._quality = 0;
        _this.quality = quality || 4;
        _this.strength = strength || 8;
        _this.firstRun = true;
        return _this;
    }
    Object.defineProperty(BlurXFilter.prototype, "blur", {
        /**
         * Sets the strength of both the blur.
         *
         * @member {number}
         * @default 16
         */
        get: function () {
            return this.strength;
        },
        set: function (value) {
            this.padding = Math.abs(value) * 2;
            this.strength = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BlurXFilter.prototype, "quality", {
        /**
        * Sets the quality of the blur by modifying the number of passes. More passes means higher
        * quaility bluring but the lower the performance.
        *
        * @member {number}
        * @default 4
        */
        get: function () {
            return this._quality;
        },
        set: function (value) {
            this._quality = value;
            this.passes = value;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * Applies the filter.
     *
     * @param {FilterManager} filterManager - The manager.
     * @param {RenderTarget} input - The input target.
     * @param {RenderTarget} output - The output target.
     * @param {boolean} clear - Should the output be cleared before rendering?
     */
    BlurXFilter.prototype.apply = function (filterManager, input, output, clear) {
        if (this.firstRun) {
            var gl = filterManager.renderer.gl;
            var kernelSize = getMaxBlurKernelSize(gl);
            this.vertexSrc = generateVertBlurSource(kernelSize, true);
            this.fragmentSrc = generateFragBlurSource(kernelSize);
            this.firstRun = false;
        }
        this.uniforms.strength = (1 / output.size.width) * (output.size.width / input.size.width);
        // screen space!
        this.uniforms.strength *= this.strength;
        this.uniforms.strength /= this.passes; // / this.passes//Math.pow(1, this.passes);
        if (this.passes === 1) {
            filterManager.applyFilter(this, input, output, clear);
        }
        else {
            var renderTarget = filterManager.getRenderTarget(true);
            var flip = input;
            var flop = renderTarget;
            for (var i = 0; i < this.passes - 1; i++) {
                filterManager.applyFilter(this, flip, flop, true);
                var temp = flop;
                flop = flip;
                flip = temp;
            }
            filterManager.applyFilter(this, flip, output, clear);
            filterManager.returnRenderTarget(renderTarget);
        }
    };
    return BlurXFilter;
}(Filter));

/**
 * The BlurYFilter applies a horizontal Gaussian blur to an object.
 *
 * @class
 * @extends Filter
 * @memberof filters
 */
var BlurYFilter = /** @class */ (function (_super) {
    __extends(BlurYFilter, _super);
    /**
     * @param {number} strength - The strength of the blur filter.
     * @param {number} quality - The quality of the blur filter.
     * @param {number} resolution - The resolution of the blur filter.
     * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15.
     */
    function BlurYFilter(strength, quality, resolution, kernelSize) {
        var _this = this;
        kernelSize = kernelSize || 5;
        var vertSrc = generateVertBlurSource(kernelSize, false);
        var fragSrc = generateFragBlurSource(kernelSize);
        _this = _super.call(this, 
        // vertex shader
        vertSrc, 
        // fragment shader
        fragSrc) || this;
        _this.resolution = resolution || 1;
        _this._quality = 0;
        _this.quality = quality || 4;
        _this.strength = strength || 8;
        _this.firstRun = true;
        return _this;
    }
    Object.defineProperty(BlurYFilter.prototype, "blur", {
        /**
         * Sets the strength of both the blur.
         *
         * @member {number}
         * @default 2
         */
        get: function () {
            return this.strength;
        },
        set: function (value) {
            this.padding = Math.abs(value) * 2;
            this.strength = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BlurYFilter.prototype, "quality", {
        /**
         * Sets the quality of the blur by modifying the number of passes. More passes means higher
         * quaility bluring but the lower the performance.
         *
         * @member {number}
         * @default 4
         */
        get: function () {
            return this._quality;
        },
        set: function (value) {
            this._quality = value;
            this.passes = value;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * Applies the filter.
     *
     * @param {FilterManager} filterManager - The manager.
     * @param {RenderTarget} input - The input target.
     * @param {RenderTarget} output - The output target.
     * @param {boolean} clear - Should the output be cleared before rendering?
     */
    BlurYFilter.prototype.apply = function (filterManager, input, output, clear) {
        if (this.firstRun) {
            var gl = filterManager.renderer.gl;
            var kernelSize = getMaxBlurKernelSize(gl);
            this.vertexSrc = generateVertBlurSource(kernelSize, false);
            this.fragmentSrc = generateFragBlurSource(kernelSize);
            this.firstRun = false;
        }
        this.uniforms.strength = (1 / output.size.height) * (output.size.height / input.size.height);
        this.uniforms.strength *= this.strength;
        this.uniforms.strength /= this.passes;
        if (this.passes === 1) {
            filterManager.applyFilter(this, input, output, clear);
        }
        else {
            var renderTarget = filterManager.getRenderTarget(true);
            var flip = input;
            var flop = renderTarget;
            for (var i = 0; i < this.passes - 1; i++) {
                filterManager.applyFilter(this, flip, flop, true);
                var temp = flop;
                flop = flip;
                flip = temp;
            }
            filterManager.applyFilter(this, flip, output, clear);
            filterManager.returnRenderTarget(renderTarget);
        }
    };
    return BlurYFilter;
}(Filter));

/**
 * The BlurFilter applies a Gaussian blur to an object.
 * The strength of the blur can be set for x- and y-axis separately.
 *
 * @class
 * @extends Filter
 * @memberof filters
 */
var BlurFilter = /** @class */ (function (_super) {
    __extends(BlurFilter, _super);
    /**
     * @param {number} strength - The strength of the blur filter.
     * @param {number} quality - The quality of the blur filter.
     * @param {number} resolution - The resolution of the blur filter.
     * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15.
     */
    function BlurFilter(strength, quality, resolution, kernelSize) {
        var _this = _super.call(this) || this;
        _this.blurXFilter = new BlurXFilter(strength, quality, resolution, kernelSize);
        _this.blurYFilter = new BlurYFilter(strength, quality, resolution, kernelSize);
        _this.padding = 0;
        _this.resolution = resolution || 1;
        _this.quality = quality || 4;
        _this.blur = strength || 8;
        return _this;
    }
    /**
     * Applies the filter.
     *
     * @param {FilterManager} filterManager - The manager.
     * @param {RenderTarget} input - The input target.
     * @param {RenderTarget} output - The output target.
     */
    BlurFilter.prototype.apply = function (filterManager, input, output) {
        var renderTarget = filterManager.getRenderTarget(true);
        this.blurXFilter.apply(filterManager, input, renderTarget, true);
        this.blurYFilter.apply(filterManager, renderTarget, output, false);
        filterManager.returnRenderTarget(renderTarget);
    };
    Object.defineProperty(BlurFilter.prototype, "blur", {
        /**
         * Sets the strength of both the blurX and blurY properties simultaneously
         *
         * @member {number}
         * @default 2
         */
        get: function () {
            return this.blurXFilter.blur;
        },
        set: function (value) {
            this.blurXFilter.blur = this.blurYFilter.blur = value;
            this.padding = Math.max(Math.abs(this.blurXFilter.strength), Math.abs(this.blurYFilter.strength)) * 2;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BlurFilter.prototype, "quality", {
        /**
         * Sets the number of passes for blur. More passes means higher quaility bluring.
         *
         * @member {number}
         * @default 1
         */
        get: function () {
            return this.blurXFilter.quality;
        },
        set: function (value) {
            this.blurXFilter.quality = this.blurYFilter.quality = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BlurFilter.prototype, "blurX", {
        /**
         * Sets the strength of the blurX property
         *
         * @member {number}
         * @default 2
         */
        get: function () {
            return this.blurXFilter.blur;
        },
        set: function (value) {
            this.blurXFilter.blur = value;
            this.padding = Math.max(Math.abs(this.blurXFilter.strength), Math.abs(this.blurYFilter.strength)) * 2;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BlurFilter.prototype, "blurY", {
        /**
         * Sets the strength of the blurY property
         *
         * @member {number}
         * @default 2
         */
        get: function () {
            return this.blurYFilter.blur;
        },
        set: function (value) {
            this.blurYFilter.blur = value;
            this.padding = Math.max(Math.abs(this.blurXFilter.strength), Math.abs(this.blurYFilter.strength)) * 2;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BlurFilter.prototype, "blendMode", {
        /**
         * Sets the blendmode of the filter
         *
         * @member {number}
         * @default BLEND_MODES.NORMAL
         */
        get: function () {
            return this.blurYFilter.blendMode;
        },
        set: function (value) {
            this.blurYFilter.blendMode = value;
        },
        enumerable: false,
        configurable: true
    });
    return BlurFilter;
}(Filter));

var colorMatrixFrag = 'precision mediump float;' +
    'varying vec2 vTextureCoord;' +
    'uniform sampler2D uSampler;' +
    'uniform float m[20];' +
    'uniform float uAlpha;' +
    'void main(void){' +
    'vec4 c = texture2D(uSampler, vTextureCoord);' +
    'if (uAlpha == 0.0) {' +
    'gl_FragColor = c;' +
    'return;' +
    '}' +
    // Un-premultiply alpha before applying the color matrix. See issue #3539.
    'if (c.a > 0.0) {' +
    'c.rgb /= c.a;' +
    '}' +
    'vec4 result;' +
    'result.r = (m[0] * c.r);' +
    'result.r += (m[1] * c.g);' +
    'result.r += (m[2] * c.b);' +
    'result.r += (m[3] * c.a);' +
    'result.r += m[4];' +
    'result.g = (m[5] * c.r);' +
    'result.g += (m[6] * c.g);' +
    'result.g += (m[7] * c.b);' +
    'result.g += (m[8] * c.a);' +
    'result.g += m[9];' +
    'result.b = (m[10] * c.r);' +
    'result.b += (m[11] * c.g);' +
    'result.b += (m[12] * c.b);' +
    'result.b += (m[13] * c.a);' +
    'result.b += m[14];' +
    'result.a = (m[15] * c.r);' +
    'result.a += (m[16] * c.g);' +
    'result.a += (m[17] * c.b);' +
    'result.a += (m[18] * c.a);' +
    'result.a += m[19];' +
    'vec3 rgb = mix(c.rgb, result.rgb, uAlpha);' +
    // Premultiply alpha again.
    'rgb *= result.a;' +
    'gl_FragColor = vec4(rgb, result.a);' +
    '}';
/**
 * The ColorMatrixFilter class lets you apply a 5x4 matrix transformation on the RGBA
 * color and alpha values of every pixel on your displayObject to produce a result
 * with a new set of RGBA color and alpha values. It's pretty powerful!
 *
 * ```js
 *  let colorMatrix = new filters.ColorMatrixFilter();
 *  container.filters = [colorMatrix];
 *  colorMatrix.contrast(2);
 * ```
 * @author Clément Chenebault <clement@goodboydigital.com>
 * @class
 * @extends Filter
 */
var ColorMatrixFilter = /** @class */ (function (_super) {
    __extends(ColorMatrixFilter, _super);
    /**
     *
     */
    function ColorMatrixFilter(colorMatrix) {
        var _this = _super.call(this, defaultVert, colorMatrixFrag) || this;
        _this.uniforms.m = colorMatrix || [
            1, 0, 0, 0, 0,
            0, 1, 0, 0, 0,
            0, 0, 1, 0, 0,
            0, 0, 0, 1, 0
        ];
        _this.alpha = 1;
        return _this;
    }
    /**
     * Transforms current matrix and set the new one
     *
     * @param {number[]} matrix - 5x4 matrix
     * @param {boolean} multiply - if true, current matrix and matrix are multiplied. If false,
     *  just set the current matrix with @param matrix
     */
    ColorMatrixFilter.prototype._loadMatrix = function (matrix, multiply) {
        if (multiply === void 0) { multiply = false; }
        var newMatrix = matrix;
        if (multiply) {
            this._multiply(newMatrix, this.uniforms.m, matrix);
            newMatrix = this._colorMatrix(newMatrix);
        }
        // set the new matrix
        this.uniforms.m = newMatrix;
    };
    /**
     * Multiplies two mat5's
     *
     * @private
     * @param {number[]} out - 5x4 matrix the receiving matrix
     * @param {number[]} a - 5x4 matrix the first operand
     * @param {number[]} b - 5x4 matrix the second operand
     * @returns {number[]} 5x4 matrix
     */
    ColorMatrixFilter.prototype._multiply = function (out, a, b) {
        // Red Channel
        out[0] = (a[0] * b[0]) + (a[1] * b[5]) + (a[2] * b[10]) + (a[3] * b[15]);
        out[1] = (a[0] * b[1]) + (a[1] * b[6]) + (a[2] * b[11]) + (a[3] * b[16]);
        out[2] = (a[0] * b[2]) + (a[1] * b[7]) + (a[2] * b[12]) + (a[3] * b[17]);
        out[3] = (a[0] * b[3]) + (a[1] * b[8]) + (a[2] * b[13]) + (a[3] * b[18]);
        out[4] = (a[0] * b[4]) + (a[1] * b[9]) + (a[2] * b[14]) + (a[3] * b[19]) + a[4];
        // Green Channel
        out[5] = (a[5] * b[0]) + (a[6] * b[5]) + (a[7] * b[10]) + (a[8] * b[15]);
        out[6] = (a[5] * b[1]) + (a[6] * b[6]) + (a[7] * b[11]) + (a[8] * b[16]);
        out[7] = (a[5] * b[2]) + (a[6] * b[7]) + (a[7] * b[12]) + (a[8] * b[17]);
        out[8] = (a[5] * b[3]) + (a[6] * b[8]) + (a[7] * b[13]) + (a[8] * b[18]);
        out[9] = (a[5] * b[4]) + (a[6] * b[9]) + (a[7] * b[14]) + (a[8] * b[19]) + a[9];
        // Blue Channel
        out[10] = (a[10] * b[0]) + (a[11] * b[5]) + (a[12] * b[10]) + (a[13] * b[15]);
        out[11] = (a[10] * b[1]) + (a[11] * b[6]) + (a[12] * b[11]) + (a[13] * b[16]);
        out[12] = (a[10] * b[2]) + (a[11] * b[7]) + (a[12] * b[12]) + (a[13] * b[17]);
        out[13] = (a[10] * b[3]) + (a[11] * b[8]) + (a[12] * b[13]) + (a[13] * b[18]);
        out[14] = (a[10] * b[4]) + (a[11] * b[9]) + (a[12] * b[14]) + (a[13] * b[19]) + a[14];
        // Alpha Channel
        out[15] = (a[15] * b[0]) + (a[16] * b[5]) + (a[17] * b[10]) + (a[18] * b[15]);
        out[16] = (a[15] * b[1]) + (a[16] * b[6]) + (a[17] * b[11]) + (a[18] * b[16]);
        out[17] = (a[15] * b[2]) + (a[16] * b[7]) + (a[17] * b[12]) + (a[18] * b[17]);
        out[18] = (a[15] * b[3]) + (a[16] * b[8]) + (a[17] * b[13]) + (a[18] * b[18]);
        out[19] = (a[15] * b[4]) + (a[16] * b[9]) + (a[17] * b[14]) + (a[18] * b[19]) + a[19];
        return out;
    };
    /**
     * Create a Float32 Array and normalize the offset component to 0-1
     *
     * @private
     * @param {number[]} matrix - 5x4 matrix
     * @return {number[]} 5x4 matrix with all values between 0-1
     */
    ColorMatrixFilter.prototype._colorMatrix = function (matrix) {
        // Create a Float32 Array and normalize the offset component to 0-1
        var m = new Float32Array(matrix);
        m[4] /= 255;
        m[9] /= 255;
        m[14] /= 255;
        m[19] /= 255;
        return m;
    };
    /**
     * Adjusts brightness
     *
     * @param {number} b - value of the brigthness (0-1, where 0 is black)
     * @param {boolean} multiply - if true, current matrix and matrix are multiplied. If false,
     *  just set the current matrix with @param matrix
     */
    ColorMatrixFilter.prototype.brightness = function (b, multiply) {
        var matrix = [
            b, 0, 0, 0, 0,
            0, b, 0, 0, 0,
            0, 0, b, 0, 0,
            0, 0, 0, 1, 0,
        ];
        this._loadMatrix(matrix, multiply);
    };
    /**
     * Set the matrices in grey scales
     *
     * @param {number} scale - value of the grey (0-1, where 0 is black)
     * @param {boolean} multiply - if true, current matrix and matrix are multiplied. If false,
     *  just set the current matrix with @param matrix
     */
    ColorMatrixFilter.prototype.greyscale = function (scale, multiply) {
        var matrix = [
            scale, scale, scale, 0, 0,
            scale, scale, scale, 0, 0,
            scale, scale, scale, 0, 0,
            0, 0, 0, 1, 0,
        ];
        this._loadMatrix(matrix, multiply);
    };
    /**
     * Set the black and white matrice.
     *
     * @param {boolean} multiply - if true, current matrix and matrix are multiplied. If false,
     *  just set the current matrix with @param matrix
     */
    ColorMatrixFilter.prototype.blackAndWhite = function (multiply) {
        var matrix = [
            0.3, 0.6, 0.1, 0, 0,
            0.3, 0.6, 0.1, 0, 0,
            0.3, 0.6, 0.1, 0, 0,
            0, 0, 0, 1, 0,
        ];
        this._loadMatrix(matrix, multiply);
    };
    /**
     * Set the hue property of the color
     *
     * @param {number} rotation - in degrees
     * @param {boolean} multiply - if true, current matrix and matrix are multiplied. If false,
     *  just set the current matrix with @param matrix
     */
    ColorMatrixFilter.prototype.hue = function (rotation, multiply) {
        rotation = (rotation || 0) / 180 * Math.PI;
        var cosR = Math.cos(rotation);
        var sinR = Math.sin(rotation);
        var sqrt = Math.sqrt;
        /* a good approximation for hue rotation
         This matrix is far better than the versions with magic luminance constants
         formerly used here, but also used in the starling framework (flash) and known from this
         old part of the internet: quasimondo.com/archives/000565.php

         This new matrix is based on rgb cube rotation in space. Look here for a more descriptive
         implementation as a shader not a general matrix:
         https://github.com/evanw/glfx.js/blob/58841c23919bd59787effc0333a4897b43835412/src/filters/adjust/huesaturation.js

         This is the source for the code:
         see http://stackoverflow.com/questions/8507885/shift-hue-of-an-rgb-color/8510751#8510751
         */
        var w = 1 / 3;
        var sqrW = sqrt(w); // weight is
        var a00 = cosR + ((1.0 - cosR) * w);
        var a01 = (w * (1.0 - cosR)) - (sqrW * sinR);
        var a02 = (w * (1.0 - cosR)) + (sqrW * sinR);
        var a10 = (w * (1.0 - cosR)) + (sqrW * sinR);
        var a11 = cosR + (w * (1.0 - cosR));
        var a12 = (w * (1.0 - cosR)) - (sqrW * sinR);
        var a20 = (w * (1.0 - cosR)) - (sqrW * sinR);
        var a21 = (w * (1.0 - cosR)) + (sqrW * sinR);
        var a22 = cosR + (w * (1.0 - cosR));
        var matrix = [
            a00, a01, a02, 0, 0,
            a10, a11, a12, 0, 0,
            a20, a21, a22, 0, 0,
            0, 0, 0, 1, 0,
        ];
        this._loadMatrix(matrix, multiply);
    };
    /**
     * Set the contrast matrix, increase the separation between dark and bright
     * Increase contrast : shadows darker and highlights brighter
     * Decrease contrast : bring the shadows up and the highlights down
     *
     * @param {number} amount - value of the contrast (0-1)
     * @param {boolean} multiply - if true, current matrix and matrix are multiplied. If false,
     *  just set the current matrix with @param matrix
     */
    ColorMatrixFilter.prototype.contrast = function (amount, multiply) {
        var v = (amount || 0) + 1;
        var o = -0.5 * (v - 1);
        var matrix = [
            v, 0, 0, 0, o,
            0, v, 0, 0, o,
            0, 0, v, 0, o,
            0, 0, 0, 1, 0,
        ];
        this._loadMatrix(matrix, multiply);
    };
    /**
     * Set the saturation matrix, increase the separation between colors
     * Increase saturation : increase contrast, brightness, and sharpness
     *
     * @param {number} amount - The saturation amount (0-1)
     * @param {boolean} multiply - if true, current matrix and matrix are multiplied. If false,
     *  just set the current matrix with @param matrix
     */
    ColorMatrixFilter.prototype.saturate = function (amount, multiply) {
        if (amount === void 0) { amount = 0; }
        var x = (amount * 2 / 3) + 1;
        var y = ((x - 1) * -0.5);
        var matrix = [
            x, y, y, 0, 0,
            y, x, y, 0, 0,
            y, y, x, 0, 0,
            0, 0, 0, 1, 0,
        ];
        this._loadMatrix(matrix, multiply);
    };
    /**
     * Desaturate image (remove color)
     *
     * Call the saturate function
     *
     */
    ColorMatrixFilter.prototype.desaturate = function () {
        this.saturate(-1);
    };
    /**
     * Negative image (inverse of classic rgb matrix)
     *
     * @param {boolean} multiply - if true, current matrix and matrix are multiplied. If false,
     *  just set the current matrix with @param matrix
     */
    ColorMatrixFilter.prototype.negative = function (multiply) {
        var matrix = [
            -1, 0, 0, 1, 0,
            0, -1, 0, 1, 0,
            0, 0, -1, 1, 0,
            0, 0, 0, 1, 0,
        ];
        this._loadMatrix(matrix, multiply);
    };
    /**
     * Sepia image
     *
     * @param {boolean} multiply - if true, current matrix and matrix are multiplied. If false,
     *  just set the current matrix with @param matrix
     */
    ColorMatrixFilter.prototype.sepia = function (multiply) {
        var matrix = [
            0.393, 0.7689999, 0.18899999, 0, 0,
            0.349, 0.6859999, 0.16799999, 0, 0,
            0.272, 0.5339999, 0.13099999, 0, 0,
            0, 0, 0, 1, 0,
        ];
        this._loadMatrix(matrix, multiply);
    };
    /**
     * Color motion picture process invented in 1916 (thanks Dominic Szablewski)
     *
     * @param {boolean} multiply - if true, current matrix and matrix are multiplied. If false,
     *  just set the current matrix with @param matrix
     */
    ColorMatrixFilter.prototype.technicolor = function (multiply) {
        var matrix = [
            1.9125277891456083, -0.8545344976951645, -0.09155508482755585, 0, 11.793603434377337,
            -0.3087833385928097, 1.7658908555458428, -0.10601743074722245, 0, -70.35205161461398,
            -0.231103377548616, -0.7501899197440212, 1.847597816108189, 0, 30.950940869491138,
            0, 0, 0, 1, 0,
        ];
        this._loadMatrix(matrix, multiply);
    };
    /**
     * Polaroid filter
     *
     * @param {boolean} multiply - if true, current matrix and matrix are multiplied. If false,
     *  just set the current matrix with @param matrix
     */
    ColorMatrixFilter.prototype.polaroid = function (multiply) {
        var matrix = [
            1.438, -0.062, -0.062, 0, 0,
            -0.122, 1.378, -0.122, 0, 0,
            -0.016, -0.016, 1.483, 0, 0,
            0, 0, 0, 1, 0,
        ];
        this._loadMatrix(matrix, multiply);
    };
    /**
     * Filter who transforms : Red -> Blue and Blue -> Red
     *
     * @param {boolean} multiply - if true, current matrix and matrix are multiplied. If false,
     *  just set the current matrix with @param matrix
     */
    ColorMatrixFilter.prototype.toBGR = function (multiply) {
        var matrix = [
            0, 0, 1, 0, 0,
            0, 1, 0, 0, 0,
            1, 0, 0, 0, 0,
            0, 0, 0, 1, 0,
        ];
        this._loadMatrix(matrix, multiply);
    };
    /**
     * Color reversal film introduced by Eastman Kodak in 1935. (thanks Dominic Szablewski)
     *
     * @param {boolean} multiply - if true, current matrix and matrix are multiplied. If false,
     *  just set the current matrix with @param matrix
     */
    ColorMatrixFilter.prototype.kodachrome = function (multiply) {
        var matrix = [
            1.1285582396593525, -0.3967382283601348, -0.03992559172921793, 0, 63.72958762196502,
            -0.16404339962244616, 1.0835251566291304, -0.05498805115633132, 0, 24.732407896706203,
            -0.16786010706155763, -0.5603416277695248, 1.6014850761964943, 0, 35.62982807460946,
            0, 0, 0, 1, 0,
        ];
        this._loadMatrix(matrix, multiply);
    };
    /**
     * Brown delicious browni filter (thanks Dominic Szablewski)
     *
     * @param {boolean} multiply - if true, current matrix and matrix are multiplied. If false,
     *  just set the current matrix with @param matrix
     */
    ColorMatrixFilter.prototype.browni = function (multiply) {
        var matrix = [
            0.5997023498159715, 0.34553243048391263, -0.2708298674538042, 0, 47.43192855600873,
            -0.037703249837783157, 0.8609577587992641, 0.15059552388459913, 0, -36.96841498319127,
            0.24113635128153335, -0.07441037908422492, 0.44972182064877153, 0, -7.562075277591283,
            0, 0, 0, 1, 0,
        ];
        this._loadMatrix(matrix, multiply);
    };
    /**
     * Vintage filter (thanks Dominic Szablewski)
     *
     * @param {boolean} multiply - if true, current matrix and matrix are multiplied. If false,
     *  just set the current matrix with @param matrix
     */
    ColorMatrixFilter.prototype.vintage = function (multiply) {
        var matrix = [
            0.6279345635605994, 0.3202183420819367, -0.03965408211312453, 0, 9.651285835294123,
            0.02578397704808868, 0.6441188644374771, 0.03259127616149294, 0, 7.462829176470591,
            0.0466055556782719, -0.0851232987247891, 0.5241648018700465, 0, 5.159190588235296,
            0, 0, 0, 1, 0,
        ];
        this._loadMatrix(matrix, multiply);
    };
    /**
     * We don't know exactly what it does, kind of gradient map, but funny to play with!
     *
     * @param {number} desaturation - Tone values.
     * @param {number} toned - Tone values.
     * @param {string} lightColor - Tone values, example: `0xFFE580`
     * @param {string} darkColor - Tone values, example: `0xFFE580`
     * @param {boolean} multiply - if true, current matrix and matrix are multiplied. If false,
     *  just set the current matrix with @param matrix
     */
    ColorMatrixFilter.prototype.colorTone = function (desaturation, toned, lightColor, darkColor, multiply) {
        desaturation = desaturation || 0.2;
        toned = toned || 0.15;
        lightColor = lightColor || 0xFFE580;
        darkColor = darkColor || 0x338000;
        var lR = ((lightColor >> 16) & 0xFF) / 255;
        var lG = ((lightColor >> 8) & 0xFF) / 255;
        var lB = (lightColor & 0xFF) / 255;
        var dR = ((darkColor >> 16) & 0xFF) / 255;
        var dG = ((darkColor >> 8) & 0xFF) / 255;
        var dB = (darkColor & 0xFF) / 255;
        var matrix = [
            0.3, 0.59, 0.11, 0, 0,
            lR, lG, lB, desaturation, 0,
            dR, dG, dB, toned, 0,
            lR - dR, lG - dG, lB - dB, 0, 0,
        ];
        this._loadMatrix(matrix, multiply);
    };
    /**
     * Night effect
     *
     * @param {number} intensity - The intensity of the night effect.
     * @param {boolean} multiply - if true, current matrix and matrix are multiplied. If false,
     *  just set the current matrix with @param matrix
     */
    ColorMatrixFilter.prototype.night = function (intensity, multiply) {
        intensity = intensity || 0.1;
        var matrix = [
            intensity * (-2.0), -intensity, 0, 0, 0,
            -intensity, 0, intensity, 0, 0,
            0, intensity, intensity * 2.0, 0, 0,
            0, 0, 0, 1, 0,
        ];
        this._loadMatrix(matrix, multiply);
    };
    /**
     * Predator effect
     *
     * Erase the current matrix by setting a new indepent one
     *
     * @param {number} amount - how much the predator feels his future victim
     * @param {boolean} multiply - if true, current matrix and matrix are multiplied. If false,
     *  just set the current matrix with @param matrix
     */
    ColorMatrixFilter.prototype.predator = function (amount, multiply) {
        var matrix = [
            // row 1
            11.224130630493164 * amount,
            -4.794486999511719 * amount,
            -2.8746118545532227 * amount,
            0 * amount,
            0.40342438220977783 * amount,
            // row 2
            -3.6330697536468506 * amount,
            9.193157196044922 * amount,
            -2.951810836791992 * amount,
            0 * amount,
            -1.316135048866272 * amount,
            // row 3
            -3.2184197902679443 * amount,
            -4.2375030517578125 * amount,
            7.476448059082031 * amount,
            0 * amount,
            0.8044459223747253 * amount,
            // row 4
            0, 0, 0, 1, 0,
        ];
        this._loadMatrix(matrix, multiply);
    };
    /**
     * LSD effect
     *
     * Multiply the current matrix
     *
     * @param {boolean} multiply - if true, current matrix and matrix are multiplied. If false,
     *  just set the current matrix with @param matrix
     */
    ColorMatrixFilter.prototype.lsd = function (multiply) {
        var matrix = [
            2, -0.4, 0.5, 0, 0,
            -0.5, 2, -0.4, 0, 0,
            -0.4, -0.5, 3, 0, 0,
            0, 0, 0, 1, 0,
        ];
        this._loadMatrix(matrix, multiply);
    };
    /**
     * Erase the current matrix by setting the default one
     *
     */
    ColorMatrixFilter.prototype.reset = function () {
        var matrix = [
            1, 0, 0, 0, 0,
            0, 1, 0, 0, 0,
            0, 0, 1, 0, 0,
            0, 0, 0, 1, 0,
        ];
        this._loadMatrix(matrix, false);
    };
    Object.defineProperty(ColorMatrixFilter.prototype, "matrix", {
        /**
         * The matrix of the color matrix filter
         *
         * @member {number[]}
         * @default [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0]
         */
        get: function () {
            return this.uniforms.m;
        },
        set: function (value) {
            this.uniforms.m = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(ColorMatrixFilter.prototype, "alpha", {
        /**
         * The opacity value to use when mixing the original and resultant colors.
         *
         * When the value is 0, the original color is used without modification.
         * When the value is 1, the result color is used.
         * When in the range (0, 1) the color is interpolated between the original and result by this amount.
         *
         * @member {number}
         * @default 1
         */
        get: function () {
            return this.uniforms.uAlpha;
        },
        set: function (value) {
            this.uniforms.uAlpha = value;
        },
        enumerable: false,
        configurable: true
    });
    return ColorMatrixFilter;
}(Filter));
// Americanized alias
ColorMatrixFilter.prototype.grayscale = ColorMatrixFilter.prototype.greyscale;

var alphaFrag = 'precision mediump float;' +
    'varying vec2 vTextureCoord;' +
    'uniform sampler2D uSampler;' +
    'uniform float uAlpha;' +
    'void main(void){' +
    'gl_FragColor = texture2D(uSampler, vTextureCoord) * uAlpha;' +
    '}';
/**
 * Simplest filter - applies alpha
 *
 * Use this instead of Container's alpha property to avoid visual layering of individual elements.
 * AlphaFilter applies alpha evenly across the entire display object and any opaque elements it contains.
 * If elements are not opaque, they will blend with each other anyway.
 *
 * Very handy if you want to use common features of all filters:
 *
 * 1. Assign a blendMode to this filter, blend all elements inside display object with background.
 *
 * 2. To use clipping in display coordinates, assign a filterArea to the same container that has this filter.
 *
 * @class
 * @extends Filter
 * @memberof filters
 */
var AlphaFilter = /** @class */ (function (_super) {
    __extends(AlphaFilter, _super);
    /**
     * @param {number} [alpha=1] Amount of alpha from 0 to 1, where 0 is transparent
     */
    function AlphaFilter(alpha) {
        if (alpha === void 0) { alpha = 1.0; }
        var _this = _super.call(this, defaultVert, alphaFrag) || this;
        _this.alpha = alpha;
        _this.glShaderKey = 'alpha';
        return _this;
    }
    Object.defineProperty(AlphaFilter.prototype, "alpha", {
        /**
         * Coefficient for alpha multiplication
         *
         * @member {number}
         * @default 1
         */
        get: function () {
            return this.uniforms.uAlpha;
        },
        set: function (value) {
            this.uniforms.uAlpha = value;
        },
        enumerable: false,
        configurable: true
    });
    return AlphaFilter;
}(Filter));

var tempMat = new Matrix();
/**
 * Class controls uv transform and frame clamp for texture
 * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
 * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
 *
 * @see Texture
 * @see mesh.Mesh
 * @see extras.TilingSprite
 * @class
 */
var TextureMatrix = /** @class */ (function () {
    /**
     *
     * @param {Texture} texture observed texture
     * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
     * @constructor
     */
    function TextureMatrix(texture, clampMargin) {
        if (clampMargin === void 0) { clampMargin = 0.5; }
        this._texture = texture;
        this.mapCoord = new Matrix();
        this.uClampFrame = new Float32Array(4);
        this.uClampOffset = new Float32Array(2);
        this._lastTextureID = -1;
        this.clampOffset = 0;
        this.clampMargin = clampMargin;
    }
    Object.defineProperty(TextureMatrix.prototype, "texture", {
        /**
         * texture property
         * @member {Texture}
         */
        get: function () {
            return this._texture;
        },
        set: function (value) {
            this._texture = value;
            this._lastTextureID = -1;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * Multiplies uvs array to transform
     * @param {Float32Array} uvs mesh uvs
     * @param {Float32Array} [out=uvs] output
     * @returns {Float32Array} output
     */
    TextureMatrix.prototype.multiplyUvs = function (uvs, out) {
        if (out === undefined) {
            out = uvs;
        }
        var mat = this.mapCoord;
        for (var i = 0; i < uvs.length; i += 2) {
            var x = uvs[i];
            var y = uvs[i + 1];
            out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
            out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
        }
        return out;
    };
    /**
     * updates matrices if texture was changed
     * @param {boolean} forceUpdate if true, matrices will be updated any case
     * @returns {boolean} whether or not it was updated
     */
    TextureMatrix.prototype.update = function (forceUpdate) {
        var tex = this._texture;
        if (!tex || !tex.valid) {
            return false;
        }
        if (!forceUpdate
            && this._lastTextureID === tex._updateID) {
            return false;
        }
        this._lastTextureID = tex._updateID;
        var uvs = tex._uvs;
        this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
        var orig = tex.orig;
        var trim = tex.trim;
        if (trim) {
            tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height, -trim.x / trim.width, -trim.y / trim.height);
            this.mapCoord.append(tempMat);
        }
        var texBase = tex.baseTexture;
        var frame = this.uClampFrame;
        var margin = this.clampMargin;
        var offset = this.clampOffset;
        frame[0] = (tex._frame.x + margin + offset) / texBase.width;
        frame[1] = (tex._frame.y + margin + offset) / texBase.height;
        frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
        frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
        this.uClampOffset[0] = offset / texBase.width;
        this.uClampOffset[1] = offset / texBase.height;
        return true;
    };
    return TextureMatrix;
}());

var spriteMaskFilterFrag = "precision mediump float;" + //片元着色器用到浮点数必须设置精度
    "varying vec2 vMaskCoord;" +
    "varying vec2 vTextureCoord;" +
    "uniform sampler2D uSampler;" +
    "uniform sampler2D mask;" +
    "uniform float alpha;" +
    "uniform vec4 maskClamp;" +
    "void main(void){" +
    "float clip = step(3.5," +
    "step(maskClamp.x, vMaskCoord.x) +" +
    "step(maskClamp.y, vMaskCoord.y) +" +
    "step(vMaskCoord.x, maskClamp.z) +" +
    "step(vMaskCoord.y, maskClamp.w));" +
    "vec4 original = texture2D(uSampler, vTextureCoord);" +
    "vec4 masky = texture2D(mask, vMaskCoord);" +
    // "original *= (masky.r * masky.a * alpha * clip);" +
    "original *= (masky.a * alpha * clip);" + //不管r分量，不晓得为啥干进来
    "gl_FragColor = original;" +
    "}";
var spriteMaskFilterVert = "attribute vec2 aVertexPosition;" +
    "attribute vec2 aTextureCoord;" +
    "uniform mat3 projectionMatrix;" +
    "uniform mat3 otherMatrix;" +
    "varying vec2 vMaskCoord;" +
    "varying vec2 vTextureCoord;" +
    "void main(void){" +
    "gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);" +
    "vTextureCoord = aTextureCoord;" +
    "vMaskCoord = ( otherMatrix * vec3( aTextureCoord, 1.0)  ).xy;" +
    "}";
/**
 * The SpriteMaskFilter class
 *
 * @class
 * @extends Filter
 */
var SpriteMaskFilter = /** @class */ (function (_super) {
    __extends(SpriteMaskFilter, _super);
    /**
     * @param {Sprite} sprite - the target sprite
     */
    function SpriteMaskFilter(sprite) {
        var _this = this;
        var maskMatrix = new Matrix();
        _this = _super.call(this, spriteMaskFilterVert, spriteMaskFilterFrag) || this;
        sprite.renderable = false;
        _this.maskSprite = sprite;
        _this.maskMatrix = maskMatrix;
        return _this;
    }
    /**
     * Applies the filter
     *
     * @param {FilterManager} filterManager - The renderer to retrieve the filter from
     * @param {RenderTarget} input - The input render target.
     * @param {RenderTarget} output - The target to output to.
     */
    SpriteMaskFilter.prototype.apply = function (filterManager, input, output) {
        var maskSprite = this.maskSprite;
        var tex = this.maskSprite.texture;
        //如果纹理没有，或者不可用
        if (!tex || !tex.valid)
            return;
        if (!tex.transform) {
            // margin = 0.0, let it bleed a bit, shader code becomes easier
            // assuming that atlas textures were made with 1-pixel padding
            tex.transform = new TextureMatrix(tex, 0.0);
        }
        tex.transform.update();
        this.uniforms.mask = tex;
        this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
            .prepend(tex.transform.mapCoord);
        this.uniforms.alpha = maskSprite._worldAlpha;
        this.uniforms.maskClamp = tex.transform.uClampFrame;
        filterManager.applyFilter(this, input, output);
    };
    return SpriteMaskFilter;
}(Filter));

var blurFrag = [
    "precision mediump float;",
    "varying vec2 vTextureCoord;",
    "uniform sampler2D uSampler;",
    "const float resolution=1024.0;",
    "uniform float radius;",
    "uniform vec2 dir;",
    "void main() {",
    //this will be our RGBA sum
    "vec4 sum = vec4(0.0);",
    //our original texcoord for this fragment
    "vec2 tc = vTextureCoord;",
    //the amount to blur, i.e. how far off center to sample from 
    //1.0 -> blur by one pixel
    //2.0 -> blur by two pixels, etc.
    "float blur = radius/resolution;",
    //the direction of our blur
    //(1.0, 0.0) -> x-axis blur
    //(0.0, 1.0) -> y-axis blur
    "float hstep = dir.x;",
    "float vstep = dir.y;",
    //apply blurring, using a 9-tap filter with predefined gaussian weights
    "sum += texture2D(uSampler, vec2(tc.x - 4.0*blur*hstep, tc.y - 4.0*blur*vstep)) * 0.0162162162;",
    "sum += texture2D(uSampler, vec2(tc.x - 3.0*blur*hstep, tc.y - 3.0*blur*vstep)) * 0.0540540541;",
    "sum += texture2D(uSampler, vec2(tc.x - 2.0*blur*hstep, tc.y - 2.0*blur*vstep)) * 0.1216216216;",
    "sum += texture2D(uSampler, vec2(tc.x - 1.0*blur*hstep, tc.y - 1.0*blur*vstep)) * 0.1945945946;",
    "sum += texture2D(uSampler, vec2(tc.x, tc.y)) * 0.2270270270;",
    "sum += texture2D(uSampler, vec2(tc.x + 1.0*blur*hstep, tc.y + 1.0*blur*vstep)) * 0.1945945946;",
    "sum += texture2D(uSampler, vec2(tc.x + 2.0*blur*hstep, tc.y + 2.0*blur*vstep)) * 0.1216216216;",
    "sum += texture2D(uSampler, vec2(tc.x + 3.0*blur*hstep, tc.y + 3.0*blur*vstep)) * 0.0540540541;",
    "sum += texture2D(uSampler, vec2(tc.x + 4.0*blur*hstep, tc.y + 4.0*blur*vstep)) * 0.0162162162;",
    "vec4 cc= texture2D(uSampler,vTextureCoord );",
    //discard alpha for our simple demo, multiply by vertex color and return
    "gl_FragColor =vec4(sum.rgb, cc.a);",
    "}"
].join("\n");
//简单新能高点的模糊滤镜
var BlurFilterNew = /** @class */ (function (_super) {
    __extends(BlurFilterNew, _super);
    /**
     *
     * @param blur 模糊系数 0到1
     */
    function BlurFilterNew(blur) {
        if (blur === void 0) { blur = 0.5; }
        var _this = _super.call(this, defaultVert, blurFrag) || this;
        _this.blur = blur;
        //先固定吧
        _this.uniforms.dir = [1.0, 1.0];
        return _this;
    }
    Object.defineProperty(BlurFilterNew.prototype, "blur", {
        get: function () {
            return this._blur;
        },
        /**
         * 系数0到1
         */
        set: function (value) {
            if (this._blur === value)
                return;
            if (value > 1)
                value = 1;
            if (value < 0)
                value = 0;
            this._blur = value;
            this.uniforms.radius = value * 10;
        },
        enumerable: false,
        configurable: true
    });
    return BlurFilterNew;
}(Filter));

var extractBrightnessFrag = [
    "precision mediump float;",
    'uniform sampler2D uSampler;',
    'varying vec2 vTextureCoord;',
    'uniform float threshold;',
    'void main() {',
    'vec4 color = texture2D(uSampler, vTextureCoord);',
    // A simple & fast algorithm for getting brightness.
    // It's inaccuracy , but good enought for this feature.
    'float _max = max(max(color.r, color.g), color.b);',
    'float _min = min(min(color.r, color.g), color.b);',
    'float brightness = (_max + _min) * 0.5;',
    'if(brightness > threshold) {',
    'gl_FragColor = color;',
    '} else {',
    'gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);',
    '}',
    '}'
].join("\n");
/**
 * Internal filter for AdvancedBloomFilter to get brightness.
 * @class
 * @private
 * @param {number} [threshold=0.5] Defines how bright a color needs to be extracted.
 */
var ExtractBrightnessFilter = /** @class */ (function (_super) {
    __extends(ExtractBrightnessFilter, _super);
    function ExtractBrightnessFilter(threshold) {
        if (threshold === void 0) { threshold = 0.5; }
        var _this = _super.call(this, defaultVert, extractBrightnessFrag) || this;
        _this.threshold = threshold;
        return _this;
    }
    Object.defineProperty(ExtractBrightnessFilter.prototype, "threshold", {
        /**
         * Defines how bright a color needs to be extracted.
         *
         * @member {number}
         * @default 0.5
         */
        get: function () {
            return this.uniforms.threshold;
        },
        set: function (value) {
            this.uniforms.threshold = value;
        },
        enumerable: false,
        configurable: true
    });
    return ExtractBrightnessFilter;
}(Filter));

var fragmentClamp = [
    "precision mediump float;",
    'varying vec2 vTextureCoord;',
    'uniform sampler2D uSampler;',
    'uniform vec2 uOffset;',
    'uniform vec4 filterClamp;',
    'void main(void)',
    '{',
    'vec4 color = vec4(0.0);',
    // Sample top left pixel
    'color += texture2D(uSampler, clamp(vec2(vTextureCoord.x - uOffset.x, vTextureCoord.y + uOffset.y), filterClamp.xy, filterClamp.zw));',
    // Sample top right pixel
    'color += texture2D(uSampler, clamp(vec2(vTextureCoord.x + uOffset.x, vTextureCoord.y + uOffset.y), filterClamp.xy, filterClamp.zw));',
    // Sample bottom right pixel
    'color += texture2D(uSampler, clamp(vec2(vTextureCoord.x + uOffset.x, vTextureCoord.y - uOffset.y), filterClamp.xy, filterClamp.zw));',
    // Sample bottom left pixel
    'color += texture2D(uSampler, clamp(vec2(vTextureCoord.x - uOffset.x, vTextureCoord.y - uOffset.y), filterClamp.xy, filterClamp.zw));',
    // Average
    'color *= 0.25;',
    'gl_FragColor = color;',
    '}'
].join("\n");
var fragment$2 = [
    "precision mediump float;",
    'varying vec2 vTextureCoord;',
    'uniform sampler2D uSampler;',
    'uniform vec2 uOffset;',
    'void main(void)',
    '{',
    'vec4 color = vec4(0.0);',
    // Sample top left pixel
    'color += texture2D(uSampler, vec2(vTextureCoord.x - uOffset.x, vTextureCoord.y + uOffset.y));',
    // Sample top right pixel
    'color += texture2D(uSampler, vec2(vTextureCoord.x + uOffset.x, vTextureCoord.y + uOffset.y));',
    // Sample bottom right pixel
    'color += texture2D(uSampler, vec2(vTextureCoord.x + uOffset.x, vTextureCoord.y - uOffset.y));',
    // Sample bottom left pixel
    'color += texture2D(uSampler, vec2(vTextureCoord.x - uOffset.x, vTextureCoord.y - uOffset.y));',
    // Average
    'color *= 0.25;',
    'gl_FragColor = color;',
    '}'
].join("\n");
/**
 * A much faster blur than Gaussian blur, but more complicated to use.<br>
 * ![original](../tools/screenshots/dist/original.png)![filter](../tools/screenshots/dist/kawase-blur.png)
 *
 * @see https://software.intel.com/en-us/blogs/2014/07/15/an-investigation-of-fast-real-time-gpu-based-image-blur-algorithms
 *
 * @param {number|number[]} [blur=4] - The blur of the filter. Should be greater than `0`. If
 *        value is an Array, setting kernels.
 * @param {number} [quality=3] - The quality of the filter. Should be an integer greater than `1`.
 * @param {boolean} [clamp=false] - Clamp edges, useful for removing dark edges
 *        from fullscreen filters or bleeding to the edge of filterArea.
 */
var KawaseBlurFilter = /** @class */ (function (_super) {
    __extends(KawaseBlurFilter, _super);
    function KawaseBlurFilter(blur, quality, clamp) {
        if (blur === void 0) { blur = 4; }
        if (quality === void 0) { quality = 3; }
        if (clamp === void 0) { clamp = false; }
        var _this = _super.call(this, defaultVert, clamp ? fragmentClamp : fragment$2) || this;
        _this.uniforms.uOffset = new Float32Array(2);
        _this._pixelSize = new Point();
        _this.pixelSize = 1;
        _this._clamp = clamp;
        _this._kernels = null;
        // if `blur` is array , as kernels
        if (Array.isArray(blur)) {
            _this.kernels = blur;
        }
        else {
            _this._blur = blur;
            _this.quality = quality;
        }
        return _this;
    }
    /**
     * Overrides apply
     * @private
     */
    KawaseBlurFilter.prototype.apply = function (filterManager, input, output, clear) {
        var uvX = this.pixelSize.x / input.size.width;
        var uvY = this.pixelSize.y / input.size.height;
        var offset;
        if (this._quality === 1 || this._blur === 0) {
            offset = this._kernels[0] + 0.5;
            this.uniforms.uOffset[0] = offset * uvX;
            this.uniforms.uOffset[1] = offset * uvY;
            filterManager.applyFilter(this, input, output, clear);
        }
        else {
            var renderTarget = filterManager.getRenderTarget();
            var source = input;
            var target = renderTarget;
            var tmp = void 0;
            var last = this._quality - 1;
            for (var i = 0; i < last; i++) {
                offset = this._kernels[i] + 0.5;
                this.uniforms.uOffset[0] = offset * uvX;
                this.uniforms.uOffset[1] = offset * uvY;
                filterManager.applyFilter(this, source, target, true);
                tmp = source;
                source = target;
                target = tmp;
            }
            offset = this._kernels[last] + 0.5;
            this.uniforms.uOffset[0] = offset * uvX;
            this.uniforms.uOffset[1] = offset * uvY;
            filterManager.applyFilter(this, source, output, clear);
            filterManager.returnRenderTarget(renderTarget);
        }
    };
    /**
     * Auto generate kernels by blur & quality
     * @private
     */
    KawaseBlurFilter.prototype._generateKernels = function () {
        var blur = this._blur;
        var quality = this._quality;
        var kernels = [blur];
        if (blur > 0) {
            var k = blur;
            var step = blur / quality;
            for (var i = 1; i < quality; i++) {
                k -= step;
                kernels.push(k);
            }
        }
        this._kernels = kernels;
    };
    Object.defineProperty(KawaseBlurFilter.prototype, "kernels", {
        /**
         * The kernel size of the blur filter, for advanced usage.
         *
         * @member {number[]}
         * @default [0]
         */
        get: function () {
            return this._kernels;
        },
        set: function (value) {
            if (Array.isArray(value) && value.length > 0) {
                this._kernels = value;
                this._quality = value.length;
                this._blur = Math.max.apply(Math, value);
            }
            else {
                // if value is invalid , set default value
                this._kernels = [0];
                this._quality = 1;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(KawaseBlurFilter.prototype, "clamp", {
        /**
         * Get the if the filter is clampped.
         *
         * @readonly
         * @member {boolean}
         * @default false
         */
        get: function () {
            return this._clamp;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(KawaseBlurFilter.prototype, "pixelSize", {
        get: function () {
            return this._pixelSize;
        },
        /**
         * Sets the pixel size of the filter. Large size is blurrier. For advanced usage.
         *
         * @member {Point|number|number[]}
         * @default [1, 1]
         */
        set: function (value) {
            if (typeof value === 'number') {
                this._pixelSize.x = value;
                this._pixelSize.y = value;
            }
            else if (Array.isArray(value)) {
                this._pixelSize.x = value[0];
                this._pixelSize.y = value[1];
            }
            else if (value instanceof Point) {
                this._pixelSize.x = value.x;
                this._pixelSize.y = value.y;
            }
            else {
                // if value is invalid , set default value
                this._pixelSize.x = 1;
                this._pixelSize.y = 1;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(KawaseBlurFilter.prototype, "quality", {
        /**
         * The quality of the filter, integer greater than `1`.
         *
         * @member {number}
         * @default 3
         */
        get: function () {
            return this._quality;
        },
        set: function (value) {
            this._quality = Math.max(1, Math.round(value));
            this._generateKernels();
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(KawaseBlurFilter.prototype, "blur", {
        /**
         * The amount of blur, value greater than `0`.
         *
         * @member {number}
         * @default 4
         */
        get: function () {
            return this._blur;
        },
        set: function (value) {
            this._blur = value;
            this._generateKernels();
        },
        enumerable: false,
        configurable: true
    });
    return KawaseBlurFilter;
}(Filter));

var fragment$1 = [
    "precision mediump float;",
    'uniform sampler2D uSampler;',
    'varying vec2 vTextureCoord;',
    'uniform sampler2D bloomTexture;',
    'uniform float bloomScale;',
    'uniform float brightness;',
    'void main() {',
    'vec4 color = texture2D(uSampler, vTextureCoord);',
    'color.rgb *= brightness;',
    'vec4 bloomColor = vec4(texture2D(bloomTexture, vTextureCoord).rgb, 0.0);',
    'bloomColor.rgb *= bloomScale;',
    'gl_FragColor = color + bloomColor;',
    '}'
].join("\n");
/**
 * The AdvancedBloomFilter applies a Bloom Effect to an object. Unlike the normal BloomFilter
 * this had some advanced controls for adjusting the look of the bloom. Note: this filter
 * is slower than normal BloomFilter.<br>
 * ![original](../tools/screenshots/dist/original.png)![filter](../tools/screenshots/dist/advanced-bloom.png)
 *
 * @param {object|number} [options] - The optional parameters of advanced bloom filter.
 *                        When options is a number , it will be `options.threshold`.
 * @param {number} [options.threshold=0.5] - Defines how bright a color needs to be to affect bloom.
 * @param {number} [options.bloomScale=1.0] - To adjust the strength of the bloom. Higher values is more intense brightness.
 * @param {number} [options.brightness=1.0] - The brightness, lower value is more subtle brightness, higher value is blown-out.
 * @param {number} [options.blur=8] - Sets the strength of the Blur properties simultaneously
 * @param {number} [options.quality=4] - The quality of the Blur filter.
 * @param {number[]} [options.kernels=null] - The kernels of the Blur filter.
 * @param {number|number[]|Point} [options.pixelSize=1] - the pixelSize of the Blur filter.
 * @param {number} [options.resolution=1] - The resolution of the Blur filter.
 */
var AdvancedBloomFilter = /** @class */ (function (_super) {
    __extends(AdvancedBloomFilter, _super);
    // private _resolution: number;
    function AdvancedBloomFilter(options) {
        var _this = _super.call(this, defaultVert, fragment$1) || this;
        if (typeof options === 'number') {
            options = { threshold: options };
        }
        // options = Object["assign"]({
        //     threshold: 0.5,
        //     bloomScale: 1.0,
        //     brightness: 1.0,
        //     kernels: null,
        //     blur: 8,
        //     quality: 4,
        //     pixelSize: 1,
        //     resolution: 1,
        // }, options);
        //替换成...
        options = __assign({ threshold: 0.5, bloomScale: 1.0, brightness: 1.0, kernels: null, blur: 8, quality: 4, pixelSize: 1, resolution: 1 }, options);
        /**
         * To adjust the strength of the bloom. Higher values is more intense brightness.
         *
         * @member {number}
         * @default 1.0
         */
        _this.bloomScale = options.bloomScale;
        /**
         * The brightness, lower value is more subtle brightness, higher value is blown-out.
         *
         * @member {number}
         * @default 1.0
         */
        _this.brightness = options.brightness;
        var kernels = options.kernels, blur = options.blur, quality = options.quality, pixelSize = options.pixelSize, resolution = options.resolution;
        _this._extractFilter = new ExtractBrightnessFilter(options.threshold);
        _this._extractFilter.resolution = resolution;
        _this._blurFilter = kernels ?
            new KawaseBlurFilter(kernels) :
            new KawaseBlurFilter(blur, quality);
        _this.pixelSize = pixelSize;
        _this.resolution = resolution;
        return _this;
    }
    /**
     * Override existing apply method in Filter
     * @private
     */
    AdvancedBloomFilter.prototype.apply = function (filterManager, input, output, clear) {
        var brightTarget = filterManager.getRenderTarget();
        this._extractFilter.apply(filterManager, input, brightTarget, true);
        var bloomTarget = filterManager.getRenderTarget();
        this._blurFilter.apply(filterManager, brightTarget, bloomTarget, true);
        this.uniforms.bloomScale = this.bloomScale;
        this.uniforms.brightness = this.brightness;
        this.uniforms.bloomTexture = bloomTarget;
        filterManager.applyFilter(this, input, output, clear);
        filterManager.returnRenderTarget(bloomTarget);
        filterManager.returnRenderTarget(brightTarget);
    };
    Object.defineProperty(AdvancedBloomFilter.prototype, "resolution", {
        /**
         * The resolution of the filter.
         *
         * @member {number}
         */
        get: function () {
            return this._resolution;
        },
        set: function (value) {
            this._resolution = value;
            if (this._extractFilter) {
                this._extractFilter.resolution = value;
            }
            if (this._blurFilter) {
                this._blurFilter.resolution = value;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(AdvancedBloomFilter.prototype, "threshold", {
        /**
         * Defines how bright a color needs to be to affect bloom.
         *
         * @member {number}
         * @default 0.5
         */
        get: function () {
            return this._extractFilter.threshold;
        },
        set: function (value) {
            this._extractFilter.threshold = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(AdvancedBloomFilter.prototype, "kernels", {
        /**
         * Sets the kernels of the Blur Filter
         *
         * @member {number}
         * @default 4
         */
        get: function () {
            return this._blurFilter.kernels;
        },
        set: function (value) {
            this._blurFilter.kernels = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(AdvancedBloomFilter.prototype, "blur", {
        /**
         * Sets the strength of the Blur properties simultaneously
         *
         * @member {number}
         * @default 2
         */
        get: function () {
            return this._blurFilter.blur;
        },
        set: function (value) {
            this._blurFilter.blur = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(AdvancedBloomFilter.prototype, "quality", {
        /**
         * Sets the quality of the Blur Filter
         *
         * @member {number}
         * @default 4
         */
        get: function () {
            return this._blurFilter.quality;
        },
        set: function (value) {
            this._blurFilter.quality = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(AdvancedBloomFilter.prototype, "pixelSize", {
        /**
         * Sets the pixelSize of the Kawase Blur filter
         *
         * @member {number|number[]|Point}
         * @default 1
         */
        get: function () {
            return this._blurFilter.pixelSize;
        },
        set: function (value) {
            this._blurFilter.pixelSize = value;
        },
        enumerable: false,
        configurable: true
    });
    return AdvancedBloomFilter;
}(Filter));

var adjustmentFrag = [
    "precision mediump float;",
    'varying vec2 vTextureCoord;',
    'uniform sampler2D uSampler;',
    'uniform float gamma;',
    'uniform float contrast;',
    'uniform float saturation;',
    'uniform float brightness;',
    'uniform float red;',
    'uniform float green;',
    'uniform float blue;',
    'uniform float alpha;',
    'void main(void)',
    '{',
    'vec4 c = texture2D(uSampler, vTextureCoord);',
    'if (c.a > 0.0) {',
    'c.rgb /= c.a;',
    'vec3 rgb = pow(c.rgb, vec3(1. / gamma));',
    'rgb = mix(vec3(.5), mix(vec3(dot(vec3(.2125, .7154, .0721), rgb)), rgb, saturation), contrast);',
    'rgb.r *= red;',
    'rgb.g *= green;',
    'rgb.b *= blue;',
    'c.rgb = rgb * brightness;',
    'c.rgb *= c.a;',
    '}',
    'gl_FragColor = c * alpha;',
    '}'
].join("\n");
/**
 *
 * @param {object} [options] - The optional parameters of the filter.
 * @param {number} [options.gamma=1] - The amount of luminance
 * @param {number} [options.saturation=1] - The amount of color saturation
 * @param {number} [options.contrast=1] - The amount of contrast
 * @param {number} [options.brightness=1] - The overall brightness
 * @param {number} [options.red=1] - The multipled red channel
 * @param {number} [options.green=1] - The multipled green channel
 * @param {number} [options.blue=1] - The multipled blue channel
 * @param {number} [options.alpha=1] - The overall alpha amount
 */
var AdjustmentFilter = /** @class */ (function (_super) {
    __extends(AdjustmentFilter, _super);
    function AdjustmentFilter(options) {
        var _this = _super.call(this, defaultVert, adjustmentFrag) || this;
        /**
         * The amount of luminance
         * @member {number}
         * @memberof filters.AdjustmentFilter#
         * @default 1
         */
        _this.gamma = 1;
        /**
         * The amount of saturation
         * @member {number}
         * @memberof filters.AdjustmentFilter#
         * @default 1
         */
        _this.saturation = 1;
        /**
         * The amount of contrast
         * @member {number}
         * @memberof filters.AdjustmentFilter#
         * @default 1
         */
        _this.contrast = 1;
        /**
         * The amount of brightness
         * @member {number}
         * @memberof filters.AdjustmentFilter#
         * @default 1
         */
        _this.brightness = 1;
        /**
         * The amount of red channel
         * @member {number}
         * @memberof filters.AdjustmentFilter#
         * @default 1
         */
        _this.red = 1;
        /**
         * The amount of green channel
         * @member {number}
         * @memberof filters.AdjustmentFilter#
         * @default 1
         */
        _this.green = 1;
        /**
         * The amount of blue channel
         * @member {number}
         * @memberof filters.AdjustmentFilter#
         * @default 1
         */
        _this.blue = 1;
        /**
         * The amount of alpha channel
         * @member {number}
         * @memberof filters.AdjustmentFilter#
         * @default 1
         */
        _this.alpha = 1;
        if (typeof options == "object") {
            Object.keys(options).forEach(function (e) { _this[e] = options[e]; });
        }
        return _this;
    }
    /**
     * Override existing apply method in Filter
     * @private
     */
    AdjustmentFilter.prototype.apply = function (filterManager, input, output, clear) {
        this.uniforms.gamma = Math.max(this.gamma, 0.0001);
        this.uniforms.saturation = this.saturation;
        this.uniforms.contrast = this.contrast;
        this.uniforms.brightness = this.brightness;
        this.uniforms.red = this.red;
        this.uniforms.green = this.green;
        this.uniforms.blue = this.blue;
        this.uniforms.alpha = this.alpha;
        filterManager.applyFilter(this, input, output, clear);
    };
    return AdjustmentFilter;
}(Filter));

/**
 * @class
 */
var MaskManager = /** @class */ (function () {
    /**
     * - The renderer this manager works for.
     */
    function MaskManager(renderer) {
        this.renderer = renderer;
        // TODO - we don't need both!
        this.scissor = false;
        this.scissorData = null;
        this.scissorRenderTarget = null;
        this.enableScissor = true;
        this.alphaMaskPool = [];
        this.alphaMaskIndex = 0;
    }
    /**
     * Applies the Mask and adds it to the current filter stack.
     *
     * @param {DisplayObject} target - Display Object to push the mask to
     * @param {Sprite|Graphics} maskData - The masking data.
     */
    MaskManager.prototype.pushMask = function (target, maskData) {
        // TODO the root check means scissor rect will not
        // be used on render textures more info here:
        // https://github.com/pixijs/js/pull/3545
        if (maskData.texture) {
            this.pushSpriteMask(target, maskData);
        }
        else
            // if (this.enableScissor
            //     && !this.scissor
            //     && this.renderer._activeRenderTarget.root
            //     && !this.renderer.stencilManager.stencilMaskStack.length
            //     && maskData.isFastRect()) {
            //     const matrix = maskData.worldMatrix;
            //     let rot = Math.atan2(matrix.b, matrix.a);
            //     // use the nearest degree!
            //     rot = Math.round(rot * (180 / Math.PI));
            //     if (rot % 90) {
            //         this.pushStencilMask(maskData);
            //     }
            //     else {
            //         this.pushScissorMask(target, maskData);
            //     }
            // }
            // else {
            this.pushStencilMask(maskData);
        // }
    };
    /**
     * Removes the last mask from the mask stack and doesn't return it.
     *
     * @param {DisplayObject} target - Display Object to pop the mask from
     * @param {Sprite|Graphics} maskData - The masking data.
     */
    MaskManager.prototype.popMask = function (target, maskData) {
        if (maskData.texture) {
            this.popSpriteMask();
        }
        else
            // if (this.enableScissor && !this.renderer.stencilManager.stencilMaskStack.length) {
            //     this.popScissorMask();
            // }
            // else {
            this.popStencilMask();
        // }
    };
    /**
     * Applies the Mask and adds it to the current filter stack.
     *
     * @param {RenderTarget} target - Display Object to push the sprite mask to
     * @param {Sprite} maskData - Sprite to be used as the mask
     */
    MaskManager.prototype.pushSpriteMask = function (target, maskData) {
        var alphaMaskFilter = this.alphaMaskPool[this.alphaMaskIndex];
        if (!alphaMaskFilter) {
            alphaMaskFilter = this.alphaMaskPool[this.alphaMaskIndex] = [new SpriteMaskFilter(maskData)];
        }
        alphaMaskFilter[0].resolution = 1;
        alphaMaskFilter[0].maskSprite = maskData;
        //存下之前的滤镜区域
        var cacheFilterArea = target.filterArea;
        //待测试 先计算如果maskData是shape要先执行updateShape，calculateBounds里会执行，这里不需要了
        // if (maskData.instanceType == "Shape") maskData.updateShape();
        //取遮罩的范围
        target.filterArea = maskData.getBounds(true);
        this.renderer.filterManager.pushFilter(target, alphaMaskFilter);
        //恢复
        target.filterArea = cacheFilterArea;
        this.alphaMaskIndex++;
    };
    /**
     * Removes the last filter from the filter stack and doesn't return it.
     *
     */
    MaskManager.prototype.popSpriteMask = function () {
        this.renderer.filterManager.popFilter();
        this.alphaMaskIndex--;
    };
    /**
     * Applies the Mask and adds it to the current filter stack.
     *
     * @param {Graphics} maskData - The masking data.
     */
    MaskManager.prototype.pushStencilMask = function (maskData) {
        this.renderer.batchManager.flush();
        this.renderer.stencilManager.pushStencil(maskData);
    };
    /**
     * Removes the last filter from the filter stack and doesn't return it.
     *
     */
    MaskManager.prototype.popStencilMask = function () {
        this.renderer.stencilManager.popStencil();
    };
    /**
     * 有bug暂不用
     * @param {DisplayObject} target - Display Object to push the mask to
     * @param {Graphics} maskData - The masking data.
     */
    MaskManager.prototype.pushScissorMask = function (target, maskData) {
        maskData.renderable = true;
        var renderTarget = this.renderer._activeRenderTarget;
        var bounds = maskData.getBounds();
        bounds.fit(renderTarget.size);
        maskData.renderable = false;
        this.renderer.gl.enable(this.renderer.gl.SCISSOR_TEST);
        this.renderer.gl.scissor(bounds.x, (renderTarget.root ? renderTarget.size.height - bounds.y - bounds.height : bounds.y), bounds.width, bounds.height);
        this.scissorRenderTarget = renderTarget;
        this.scissorData = maskData;
        this.scissor = true;
    };
    /**
     *有bug暂不用
     *
     */
    MaskManager.prototype.popScissorMask = function () {
        this.scissorRenderTarget = null;
        this.scissorData = null;
        this.scissor = false;
        // must be scissor!
        var gl = this.renderer.gl;
        gl.disable(gl.SCISSOR_TEST);
    };
    MaskManager.prototype.destroy = function () {
        this.renderer = null;
    };
    return MaskManager;
}());

/**
 * 管理模板缓存，主要用于遮罩
 * @class
 */
var StencilManager = /** @class */ (function () {
    /**
     * @param {WebGLRenderer} renderer - The renderer this manager works for.
     */
    function StencilManager(renderer) {
        this.renderer = renderer;
        this.stencilMaskStack = null;
    }
    /**
     * Changes the mask stack that is used by this manager.
     *
     * @param {Graphics[]} stencilMaskStack - The mask stack
     */
    StencilManager.prototype.setMaskStack = function (stencilMaskStack) {
        this.stencilMaskStack = stencilMaskStack;
        var gl = this.renderer.gl;
        if (stencilMaskStack.length === 0) {
            gl.disable(gl.STENCIL_TEST);
        }
        else {
            gl.enable(gl.STENCIL_TEST);
        }
    };
    /**
     * Applies the Mask and adds it to the current stencil stack. @alvin
     *
     * @param {Graphics} graphics - The mask
     */
    StencilManager.prototype.pushStencil = function (graphics) {
        this.renderer._activeRenderTarget.attachStencilBuffer();
        var gl = this.renderer.gl;
        var prevMaskCount = this.stencilMaskStack.length;
        if (prevMaskCount === 0) {
            gl.enable(gl.STENCIL_TEST);
        }
        this.stencilMaskStack.push(graphics);
        // Increment the refference stencil value where the new mask overlaps with the old ones.
        gl.colorMask(false, false, false, false);
        gl.stencilFunc(gl.EQUAL, prevMaskCount, this._getBitwiseMask());
        gl.stencilOp(gl.KEEP, gl.KEEP, gl.INCR);
        graphics.renderable = true;
        var tempAlpha = graphics._worldAlpha; //因为如果alpha为0，不会渲染，
        graphics._worldAlpha = 1;
        graphics.renderWebGL(this.renderer);
        this.renderer.batchManager.flush();
        graphics.renderable = false;
        graphics._worldAlpha = tempAlpha;
        this._useCurrent();
    };
    /**
     * Removes the last mask from the stencil stack. @alvin
     */
    StencilManager.prototype.popStencil = function () {
        var gl = this.renderer.gl;
        var graphics = this.stencilMaskStack.pop();
        if (this.stencilMaskStack.length === 0) {
            // the stack is empty!
            gl.disable(gl.STENCIL_TEST);
            gl.clear(gl.STENCIL_BUFFER_BIT);
            gl.clearStencil(0);
        }
        else {
            // Decrement the refference stencil value where the popped mask overlaps with the other ones
            gl.colorMask(false, false, false, false);
            gl.stencilOp(gl.KEEP, gl.KEEP, gl.DECR);
            graphics.renderable = true;
            var tempAlpha = graphics._worldAlpha; //因为如果alpha为0，不会渲染，
            graphics._worldAlpha = 1;
            graphics.renderWebGL(this.renderer);
            this.renderer.batchManager.flush();
            graphics.renderable = false;
            graphics._worldAlpha = tempAlpha;
            this._useCurrent();
        }
    };
    /**
     * Setup renderer to use the current stencil data.
     */
    StencilManager.prototype._useCurrent = function () {
        var gl = this.renderer.gl;
        gl.colorMask(true, true, true, true);
        gl.stencilFunc(gl.EQUAL, this.stencilMaskStack.length, this._getBitwiseMask());
        gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
    };
    /**
     * Fill 1s equal to the number of acitve stencil masks.
     *
     * @return {number} The bitwise mask.
     */
    StencilManager.prototype._getBitwiseMask = function () {
        return (1 << this.stencilMaskStack.length) - 1;
    };
    /**
     * Destroys the mask stack.
     *
     */
    StencilManager.prototype.destroy = function () {
        this.renderer = null;
        this.stencilMaskStack = null;
    };
    return StencilManager;
}());

/**
 * Generic Mask Stack data structure
 * 根据图片数量创建索引数组 ，暂时不用了
 * 0....1
 * . .  .
 * .  . .
 * 3....2
 * @function createIndicesForQuads
 * @private
 * @param {number} size - Number of quads
 * @return {Uint16Array} indices
 */
function createIndicesForQuads(size) {
    // the total number of indices in our array, there are 6 points per quad.
    var totalIndices = size * 6;
    var indices = new Uint16Array(totalIndices);
    // fill the indices with the quads to draw
    for (var i = 0, j = 0; i < totalIndices; i += 6, j += 4) {
        indices[i + 0] = j + 0;
        indices[i + 1] = j + 1;
        indices[i + 2] = j + 2;
        indices[i + 3] = j + 0;
        indices[i + 4] = j + 2;
        indices[i + 5] = j + 3;
    }
    return indices;
}

/**
 * webgl矩形数据
 * 外部基本不使用，不继承HashObject
 */
var Quad = /** @class */ (function () {
    /**
     * @param {WebGLRenderingContext} gl - The gl context for this quad to use.
     * @param {object} state - TODO: Description
     */
    function Quad(gl, state) {
        this.gl = gl;
        this.vertices = new Float32Array([
            -1, -1,
            1, -1,
            1, 1,
            -1, 1,
        ]);
        this.uvs = new Float32Array([
            0, 0,
            1, 0,
            1, 1,
            0, 1,
        ]);
        this.interleaved = new Float32Array(8 * 2);
        for (var i = 0; i < 4; i++) {
            this.interleaved[i * 4] = this.vertices[(i * 2)];
            this.interleaved[(i * 4) + 1] = this.vertices[(i * 2) + 1];
            this.interleaved[(i * 4) + 2] = this.uvs[i * 2];
            this.interleaved[(i * 4) + 3] = this.uvs[(i * 2) + 1];
        }
        this.indices = createIndicesForQuads(1);
        this.vertexBuffer = GLBuffer.createVertexBuffer(gl, this.interleaved, gl.STATIC_DRAW);
        this.indexBuffer = GLBuffer.createIndexBuffer(gl, this.indices, gl.STATIC_DRAW);
        this.vao = new VertexArrayObject(gl, state);
    }
    /**
     * 用shader初始化vao
     */
    Quad.prototype.initVao = function (shader) {
        this.vao.clear()
            .addIndex(this.indexBuffer)
            .addAttribute(this.vertexBuffer, shader.attributes.aVertexPosition, this.gl.FLOAT, false, 4 * 4, 0)
            .addAttribute(this.vertexBuffer, shader.attributes.aTextureCoord, this.gl.FLOAT, false, 4 * 4, 2 * 4);
    };
    /**
     * Maps two Rectangle to the quad.
     * @param {Rectangle} targetTextureFrame - the first rectangle
     * @param {Rectangle} destinationFrame - the second rectangle
     * @return {Quad} Returns itself.
     */
    Quad.prototype.map = function (targetTextureFrame, destinationFrame) {
        var x = 0; // destinationFrame.x / targetTextureFrame.width;
        var y = 0; // destinationFrame.y / targetTextureFrame.height;
        this.uvs[0] = x;
        this.uvs[1] = y;
        this.uvs[2] = x + (destinationFrame.width / targetTextureFrame.width);
        this.uvs[3] = y;
        this.uvs[4] = x + (destinationFrame.width / targetTextureFrame.width);
        this.uvs[5] = y + (destinationFrame.height / targetTextureFrame.height);
        this.uvs[6] = x;
        this.uvs[7] = y + (destinationFrame.height / targetTextureFrame.height);
        x = destinationFrame.x;
        y = destinationFrame.y;
        this.vertices[0] = x;
        this.vertices[1] = y;
        this.vertices[2] = x + destinationFrame.width;
        this.vertices[3] = y;
        this.vertices[4] = x + destinationFrame.width;
        this.vertices[5] = y + destinationFrame.height;
        this.vertices[6] = x;
        this.vertices[7] = y + destinationFrame.height;
        return this;
    };
    /**
     * 上传绑定数据
     * @return {Quad} Returns itself.
     */
    Quad.prototype.upload = function () {
        for (var i = 0; i < 4; i++) {
            this.interleaved[i * 4] = this.vertices[(i * 2)];
            this.interleaved[(i * 4) + 1] = this.vertices[(i * 2) + 1];
            this.interleaved[(i * 4) + 2] = this.uvs[i * 2];
            this.interleaved[(i * 4) + 3] = this.uvs[(i * 2) + 1];
        }
        this.vertexBuffer.upload(this.interleaved);
        return this;
    };
    Quad.prototype.destroy = function () {
        var gl = this.gl;
        gl.deleteBuffer(this.vertexBuffer);
        gl.deleteBuffer(this.indexBuffer);
        this.gl = null;
        this.vertices = null;
        this.uvs = null;
        this.interleaved = null;
        this.indices = null;
        this.vertexBuffer.destroy();
        this.indexBuffer.destroy();
        this.vao.destroy();
    };
    return Quad;
}());

/**
 * Calculates the mapped matrix
 * @param filterArea {Rectangle} The filter area
 * @param sprite {Sprite} the target sprite
 * @param outputMatrix {Matrix} @alvin
 * @private
 */
// TODO playing around here.. this is temporary - (will end up in the shader)
// this returns a matrix that will normalise map filter cords in the filter to screen space
function calculateScreenSpaceMatrix(outputMatrix, filterArea, textureSize) {
    // let worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX),
    // let texture = {width:1136, height:700};//sprite._texture.baseTexture;
    // TODO unwrap?
    var mappedMatrix = outputMatrix.identity();
    mappedMatrix.translate(filterArea.x / textureSize.width, filterArea.y / textureSize.height);
    mappedMatrix.scale(textureSize.width, textureSize.height);
    return mappedMatrix;
}
function calculateNormalizedScreenSpaceMatrix(outputMatrix, filterArea, textureSize) {
    var mappedMatrix = outputMatrix.identity();
    mappedMatrix.translate(filterArea.x / textureSize.width, filterArea.y / textureSize.height);
    var translateScaleX = (textureSize.width / filterArea.width);
    var translateScaleY = (textureSize.height / filterArea.height);
    mappedMatrix.scale(translateScaleX, translateScaleY);
    return mappedMatrix;
}
// this will map the filter coord so that a texture can be used based on the transform of a sprite
function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite) {
    var orig = sprite._texture.orig;
    var mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
    var worldTransform = Matrix.TEMP_MATRIX.copy(sprite.worldMatrix); //sprite.worldMatrix.copy(Matrix.TEMP_MATRIX);
    worldTransform.invert();
    mappedMatrix.prepend(worldTransform);
    mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
    mappedMatrix.translate(sprite.anchorTexture.x, sprite.anchorTexture.y);
    return mappedMatrix;
}

var FilterState = /** @class */ (function () {
    /**
     *
     */
    function FilterState() {
        this.renderTarget = null;
        this.target = null;
        this.resolution = 1;
        // those three objects are used only for root
        // re-assigned for everything else
        this.sourceFrame = new Rectangle();
        this.destinationFrame = new Rectangle();
        this.filters = [];
    }
    /**
     * clears the state
     */
    FilterState.prototype.clear = function () {
        this.filters = null;
        this.target = null;
        this.renderTarget = null;
    };
    return FilterState;
}());
var screenKey = 'screen';
var FilterManager = /** @class */ (function () {
    /**
     * @param {WebGLRenderer} renderer - The renderer this manager works for.
     */
    function FilterManager(renderer) {
        this.renderer = renderer;
        this.gl = this.renderer.gl;
        // know about sprites!
        this.quad = new Quad(this.gl, renderer.state.attribState);
        this.shaderCache = {};
        // todo add default!
        this.pool = {};
        this.filterData = null;
        this.managedFilters = [];
        this.renderer.addEventListener('onPreRender', this.onPreRender, this);
        this._screenWidth = renderer.width;
        this._screenHeight = renderer.height;
    }
    /**
     * Adds a new filter to the manager.
     *
     * @param {DisplayObject} target - The target of the filter to render.
     * @param {Filter[]} filters - The filters to apply.
     */
    FilterManager.prototype.pushFilter = function (target, filters) {
        var renderer = this.renderer;
        var filterData = this.filterData;
        if (!filterData) {
            // add new stack
            var filterState = new FilterState();
            filterState.sourceFrame = filterState.destinationFrame = this.renderer._activeRenderTarget.size;
            filterState.renderTarget = renderer._activeRenderTarget;
            this.renderer._activeRenderTarget.filterData = filterData = {
                index: 0,
                stack: [filterState],
            };
            this.filterData = filterData;
        }
        // get the current filter state..
        var currentState = filterData.stack[++filterData.index];
        var renderTargetFrame = filterData.stack[0].destinationFrame;
        if (!currentState) {
            currentState = filterData.stack[filterData.index] = new FilterState();
        }
        // const fullScreen = target.filterArea
        //     && target.filterArea.x === 0
        //     && target.filterArea.y === 0
        //     && target.filterArea.width === renderer.screen.width
        //     && target.filterArea.height === renderer.screen.height;
        // for now we go off the filter of the first resolution..
        var resolution = filters[0].resolution;
        var padding = filters[0].padding | 0;
        var targetBounds = /*fullScreen ? renderer.screen : (*/ target.filterArea || target.getBounds(true) /*)*/;
        var sourceFrame = currentState.sourceFrame;
        var destinationFrame = currentState.destinationFrame;
        sourceFrame.x = ((targetBounds.x * resolution) | 0) / resolution;
        sourceFrame.y = ((targetBounds.y * resolution) | 0) / resolution;
        sourceFrame.width = ((targetBounds.width * resolution) | 0) / resolution;
        sourceFrame.height = ((targetBounds.height * resolution) | 0) / resolution;
        // if (!fullScreen) {
        if (filterData.stack[0].renderTarget.transform) ;
        else if (filters[0].autoFit) {
            sourceFrame.fit(renderTargetFrame);
        }
        // lets apply the padding After we fit the element to the screen.
        // this should stop the strange side effects that can occur when cropping to the edges
        sourceFrame.pad(padding);
        // }
        destinationFrame.width = sourceFrame.width;
        destinationFrame.height = sourceFrame.height;
        // lets play the padding after we fit the element to the screen.
        // this should stop the strange side effects that can occur when cropping to the edges
        var renderTarget = this.getPotRenderTarget(renderer.gl, sourceFrame.width, sourceFrame.height, resolution);
        currentState.target = target;
        currentState.filters = filters;
        currentState.resolution = resolution;
        currentState.renderTarget = renderTarget;
        // bind the render target to draw the shape in the top corner..
        renderTarget.setFrame(destinationFrame, sourceFrame);
        // bind the render target
        renderer.bindRenderTarget(renderTarget);
        renderTarget.clear();
    };
    /**
     * Pops off the filter and applies it.
     *
     */
    FilterManager.prototype.popFilter = function () {
        var filterData = this.filterData;
        var lastState = filterData.stack[filterData.index - 1];
        var currentState = filterData.stack[filterData.index];
        this.quad.map(currentState.renderTarget.size, currentState.sourceFrame).upload();
        var filters = currentState.filters;
        if (filters.length === 1) {
            filters[0].apply(this, currentState.renderTarget, lastState.renderTarget, false, currentState);
            this.freePotRenderTarget(currentState.renderTarget);
        }
        else {
            var flip = currentState.renderTarget;
            var flop = this.getPotRenderTarget(this.renderer.gl, currentState.sourceFrame.width, currentState.sourceFrame.height, currentState.resolution);
            flop.setFrame(currentState.destinationFrame, currentState.sourceFrame);
            // finally lets clear the render target before drawing to it..
            flop.clear();
            var i = 0;
            for (i = 0; i < filters.length - 1; ++i) {
                filters[i].apply(this, flip, flop, true, currentState);
                var t = flip;
                flip = flop;
                flop = t;
            }
            filters[i].apply(this, flip, lastState.renderTarget, false, currentState);
            this.freePotRenderTarget(flip);
            this.freePotRenderTarget(flop);
        }
        currentState.clear();
        filterData.index--;
        if (filterData.index === 0) {
            this.filterData = null;
        }
    };
    /**
     * Draws a filter.
     *
     * @param {Filter} filter - The filter to draw.
     * @param {RenderTarget} input - The input render target.
     * @param {RenderTarget} output - The target to output to.
     * @param {boolean} clear - Should the output be cleared before rendering to it
     */
    FilterManager.prototype.applyFilter = function (filter, input, output, clear) {
        var renderer = this.renderer;
        var gl = renderer.gl;
        var shader = filter.glShaders[renderer.CONTEXT_UID];
        // cacheing..
        if (!shader) {
            if (filter.glShaderKey) {
                shader = this.shaderCache[filter.glShaderKey];
                if (!shader) {
                    shader = new GLShader(this.gl, filter.vertexSrc, filter.fragmentSrc);
                    filter.glShaders[renderer.CONTEXT_UID] = this.shaderCache[filter.glShaderKey] = shader;
                    this.managedFilters.push(filter);
                }
            }
            else {
                shader = filter.glShaders[renderer.CONTEXT_UID] = new GLShader(this.gl, filter.vertexSrc, filter.fragmentSrc);
                this.managedFilters.push(filter);
            }
            // TODO - this only needs to be done once?
            renderer.bindVao(null);
            this.quad.initVao(shader);
        }
        renderer.bindVao(this.quad.vao);
        renderer.bindRenderTarget(output);
        if (clear) {
            gl.disable(gl.SCISSOR_TEST);
            renderer.clear(); // [1, 1, 1, 1]);
            gl.enable(gl.SCISSOR_TEST);
        }
        // in case the render target is being masked using a scissor rect
        if (output === renderer.maskManager.scissorRenderTarget) {
            renderer.maskManager.pushScissorMask(null, renderer.maskManager.scissorData);
        }
        renderer.bindShader(shader);
        // free unit 0 for us, doesn't matter what was there
        // don't try to restore it, because syncUniforms can upload it to another slot
        // and it'll be a problem
        var tex = this.renderer.textureManager.emptyTextures[0];
        this.renderer.textureManager.boundTextures[0] = tex;
        // this syncs the filters  uniforms with glsl uniforms
        this.syncUniforms(shader, filter);
        renderer.state.setBlendMode(filter.blendMode);
        gl.activeTexture(gl.TEXTURE0);
        gl.bindTexture(gl.TEXTURE_2D, input.texture.texture);
        this.quad.vao.draw(this.renderer.gl.TRIANGLES, 6, 0);
        gl.bindTexture(gl.TEXTURE_2D, tex._glTextures[this.renderer.CONTEXT_UID].texture);
        //确保会重新active
        this.renderer.textureManager.currentLocation = -1;
    };
    /**
     * Uploads the uniforms of the filter.
     *
     * @param {GLShader} shader - The underlying gl shader.
     * @param {Filter} filter - The filter we are synchronizing.
     */
    FilterManager.prototype.syncUniforms = function (shader, filter) {
        var uniformData = filter.uniformData;
        var uniforms = filter.uniforms;
        // 0 is reserved for the texture so we start at 1!
        var textureCount = 1;
        var currentState;
        // filterArea and filterClamp that are handled by FilterManager directly
        // they must not appear in uniformData
        if (shader.uniforms.filterArea) {
            currentState = this.filterData.stack[this.filterData.index];
            var filterArea = shader.uniforms.filterArea;
            filterArea[0] = currentState.renderTarget.size.width;
            filterArea[1] = currentState.renderTarget.size.height;
            filterArea[2] = currentState.sourceFrame.x;
            filterArea[3] = currentState.sourceFrame.y;
            shader.uniforms.filterArea = filterArea;
        }
        // use this to clamp displaced texture coords so they belong to filterArea
        // see displacementFilter fragment shader for an example
        if (shader.uniforms.filterClamp) {
            currentState = currentState || this.filterData.stack[this.filterData.index];
            var filterClamp = shader.uniforms.filterClamp;
            filterClamp[0] = 0;
            filterClamp[1] = 0;
            filterClamp[2] = (currentState.sourceFrame.width - 1) / currentState.renderTarget.size.width;
            filterClamp[3] = (currentState.sourceFrame.height - 1) / currentState.renderTarget.size.height;
            shader.uniforms.filterClamp = filterClamp;
        }
        // TODO Cacheing layer..每次运行都要重新赋值uniform，考虑加判断
        for (var i in uniformData) {
            var type = uniformData[i].type;
            if (type === 'sampler2d' && uniforms[i] !== 0) {
                if (uniforms[i].baseTexture) {
                    shader.uniforms[i] = this.renderer.textureManager.bindTexture(uniforms[i].baseTexture, textureCount);
                }
                else {
                    shader.uniforms[i] = textureCount;
                    // TODO
                    // this is helpful as renderTargets can also be set.
                    // Although thinking about it, we could probably
                    // make the filter texture cache return a RenderTexture
                    // rather than a renderTarget
                    var gl = this.renderer.gl;
                    this.renderer.textureManager.boundTextures[textureCount] = this.renderer.textureManager.emptyTextures[textureCount];
                    gl.activeTexture(gl.TEXTURE0 + textureCount);
                    uniforms[i].texture.bind();
                }
                textureCount++;
            }
            else if (type === 'mat3') {
                // check if its matrix..
                if (uniforms[i].a !== undefined) {
                    shader.uniforms[i] = uniforms[i].toArray(true);
                }
                else {
                    shader.uniforms[i] = uniforms[i];
                }
            }
            else if (type === 'vec2') {
                // check if its a point..
                if (uniforms[i].x !== undefined) {
                    var val = shader.uniforms[i] || new Float32Array(2);
                    val[0] = uniforms[i].x;
                    val[1] = uniforms[i].y;
                    shader.uniforms[i] = val;
                }
                else {
                    shader.uniforms[i] = uniforms[i];
                }
            }
            else if (type === 'float') {
                if (shader.uniforms.data[i].value !== uniformData[i]) {
                    shader.uniforms[i] = uniforms[i];
                }
            }
            else {
                shader.uniforms[i] = uniforms[i];
            }
        }
    };
    /**
     * Gets a render target from the pool, or creates a new one.
     *
     * @param {boolean} clear - Should we clear the render texture when we get it?
     * @param {number} resolution - The resolution of the target.
     * @return {RenderTarget} The new render target
     */
    FilterManager.prototype.getRenderTarget = function (clear, resolution) {
        var currentState = this.filterData.stack[this.filterData.index];
        var renderTarget = this.getPotRenderTarget(this.renderer.gl, currentState.sourceFrame.width, currentState.sourceFrame.height, resolution || currentState.resolution);
        renderTarget.setFrame(currentState.destinationFrame, currentState.sourceFrame);
        return renderTarget;
    };
    /**
     * Returns a render target to the pool.
     *
     * @param {RenderTarget} renderTarget - The render target to return.
     */
    FilterManager.prototype.returnRenderTarget = function (renderTarget) {
        this.freePotRenderTarget(renderTarget);
    };
    /**
     * Calculates the mapped matrix.
     *
     * TODO playing around here.. this is temporary - (will end up in the shader)
     * this returns a matrix that will normalise map filter cords in the filter to screen space
     *
     * @param {Matrix} outputMatrix - the matrix to output to.
     * @return {Matrix} The mapped matrix.
     */
    FilterManager.prototype.calculateScreenSpaceMatrix = function (outputMatrix) {
        var currentState = this.filterData.stack[this.filterData.index];
        return calculateScreenSpaceMatrix(outputMatrix, currentState.sourceFrame, currentState.renderTarget.size);
    };
    /**
     * Multiply vTextureCoord to this matrix to achieve (0,0,1,1) for filterArea
     *
     * @param {Matrix} outputMatrix - The matrix to output to.
     * @return {Matrix} The mapped matrix.
     */
    FilterManager.prototype.calculateNormalizedScreenSpaceMatrix = function (outputMatrix) {
        var currentState = this.filterData.stack[this.filterData.index];
        return calculateNormalizedScreenSpaceMatrix(outputMatrix, currentState.sourceFrame, currentState.renderTarget.size);
    };
    /**
     * This will map the filter coord so that a texture can be used based on the transform of a sprite
     *
     * @param {Matrix} outputMatrix - The matrix to output to.
     * @param {Sprite} sprite - The sprite to map to.
     * @return {Matrix} The mapped matrix.
     */
    FilterManager.prototype.calculateSpriteMatrix = function (outputMatrix, sprite) {
        var currentState = this.filterData.stack[this.filterData.index];
        return calculateSpriteMatrix(outputMatrix, currentState.sourceFrame, currentState.renderTarget.size, sprite);
    };
    /**
     * Destroys this Filter Manager.
     *
     * @param {boolean} [contextLost=false] context was lost, do not free shaders
     *
     */
    FilterManager.prototype.destroy = function (contextLost) {
        if (contextLost === void 0) { contextLost = false; }
        var renderer = this.renderer;
        var filters = this.managedFilters;
        renderer.removeEventListener('onPreRender', this.onPreRender, this);
        this.renderer = null;
        for (var i = 0; i < filters.length; i++) {
            if (!contextLost) {
                filters[i].glShaders[renderer.CONTEXT_UID].destroy();
            }
            delete filters[i].glShaders[renderer.CONTEXT_UID];
        }
        this.shaderCache = {};
        if (!contextLost) {
            this.emptyPool();
        }
        else {
            this.pool = {};
        }
    };
    /**
     * Gets a Power-of-Two render texture.
     *
     * TODO move to a seperate class could be on renderer?
     * also - could cause issue with multiple contexts?
     *
     * @private
     * @param {WebGLRenderingContext} gl - The webgl rendering context
     * @param {number} minWidth - The minimum width of the render target.
     * @param {number} minHeight - The minimum height of the render target.
     * @param {number} resolution - The resolution of the render target.
     * @return {RenderTarget} The new render target.
     */
    FilterManager.prototype.getPotRenderTarget = function (gl, minWidth, minHeight, resolution) {
        var key = screenKey;
        minWidth *= resolution;
        minHeight *= resolution;
        if (minWidth !== this._screenWidth
            || minHeight !== this._screenHeight) {
            // TODO you could return a bigger texture if there is not one in the pool?
            minWidth = nextPow2(minWidth);
            minHeight = nextPow2(minHeight);
            key = ((minWidth & 0xFFFF) << 16) | (minHeight & 0xFFFF);
        }
        if (!this.pool[key]) {
            this.pool[key] = [];
        }
        var renderTarget = this.pool[key].pop();
        // creating render target will cause texture to be bound!
        if (!renderTarget) {
            // temporary bypass cache..
            var tex = this.renderer.textureManager.boundTextures[0];
            gl.activeTexture(gl.TEXTURE0);
            // internally - this will cause a texture to be bound..
            renderTarget = new RenderTarget(gl, minWidth, minHeight, undefined);
            // set the current one back
            gl.bindTexture(gl.TEXTURE_2D, tex._glTextures[this.renderer.CONTEXT_UID].texture);
            //确保会重新active
            this.renderer.textureManager.currentLocation = -1;
        }
        // manually tweak the resolution...
        // this will not modify the size of the frame buffer, just its resolution.
        renderTarget.resolution = resolution;
        renderTarget.defaultFrame.width = renderTarget.size.width = minWidth / resolution;
        renderTarget.defaultFrame.height = renderTarget.size.height = minHeight / resolution;
        renderTarget.filterPoolKey = key;
        return renderTarget;
    };
    /**
     * Empties the texture pool.
     *
     */
    FilterManager.prototype.emptyPool = function () {
        for (var i in this.pool) {
            var textures = this.pool[i];
            if (textures) {
                for (var j = 0; j < textures.length; j++) {
                    textures[j].destroy(true);
                }
            }
        }
        this.pool = {};
    };
    /**
     * Frees a render target back into the pool.
     *
     * @param {RenderTarget} renderTarget - The renderTarget to free
     */
    FilterManager.prototype.freePotRenderTarget = function (renderTarget) {
        this.pool[renderTarget.filterPoolKey].push(renderTarget);
    };
    /**
     * Called before the renderer starts rendering.
     *
     */
    FilterManager.prototype.onPreRender = function () {
        // if (this._screenWidth !== this.renderer.htmlElement.width
        //     || this._screenHeight !== this.renderer.htmlElement.height) {
        //     this._screenWidth = this.renderer.htmlElement.width;
        //     this._screenHeight = this.renderer.htmlElement.height;
        if (this._screenWidth !== this.renderer.width
            || this._screenHeight !== this.renderer.height) {
            this._screenWidth = this.renderer.width;
            this._screenHeight = this.renderer.height;
            var textures = this.pool[screenKey];
            if (textures) {
                for (var j = 0; j < textures.length; j++) {
                    textures[j].destroy(true);
                }
            }
            this.pool[screenKey] = [];
        }
    };
    return FilterManager;
}());

var CONTEXT_UID = 0;
//渲染方式基本用了pixi的方式
var WebglRenderer = /** @class */ (function (_super) {
    __extends(WebglRenderer, _super);
    /**
     * 只传入上下文和尺寸，canvas标签在stage上处理
     * @param gl
     * @param width
     * @param height
     */
    function WebglRenderer(gl, width, height) {
        var _this = _super.call(this) || this;
        /**
         * 所有插件列表，目前只有batch
         */
        _this.plugins = {};
        _this._instanceType = "WebglRenderer";
        _this.type = RENDERER_TYPE.WEBGL;
        //修改下函数this指向，stage里直接用
        _this.handleContextLost = _this.handleContextLost.bind(_this);
        _this.handleContextRestored = _this.handleContextRestored.bind(_this);
        //在stage里处理
        // this.htmlElement.addEventListener('webglcontextlost', this.handleContextLost, false);
        // this.htmlElement.addEventListener('webglcontextrestored', this.handleContextRestored, false);
        //stage上处理了
        // var contextOptions = {
        //     alpha: true,
        //     antialias: false,
        //     premultipliedAlpha: true,  //一般png图片都不会预乘alpha，所以必为true,除非有些图集工具选择了premultipliedAlpha
        //     stencil: true,
        //     preserveDrawingBuffer: false,
        //     // powerPreference: this.options.powerPreference,
        // };
        _this._backgroundColorRgba[3] = _this.transparent ? 0 : 1;
        // this.gl = createContext(this.htmlElement, contextOptions);
        _this.gl = gl;
        _this.CONTEXT_UID = CONTEXT_UID++;
        _this.maskManager = new MaskManager(_this);
        _this.stencilManager = new StencilManager(_this);
        _this.batchManager = new BatchManager(_this);
        _this.textureManager = null;
        //初始化插件
        _this.initPlugins(WebglRenderer.__plugins);
        _this.state = new WebGLState(_this.gl);
        _this.renderingToScreen = true;
        _this._activeShader = null;
        _this._activeVao = null;
        _this._activeRenderTarget = null;
        _this._initContext();
        // this.state.setBlendMode(0);
        _this.resize(width, height);
        return _this;
    }
    WebglRenderer.prototype._initContext = function () {
        var gl = this.gl;
        // restore a context if it was previously lost
        if (gl.isContextLost() && gl.getExtension('WEBGL_lose_context')) {
            gl.getExtension('WEBGL_lose_context').restoreContext();
        }
        this._activeShader = null;
        this._activeVao = null;
        // create a texture manager...
        this.textureManager = new TextureManager(this);
        this.filterManager = new FilterManager(this);
        this.textureGC = new TextureGarbageCollector(this);
        this.state.resetToDefault();
        this.rootRenderTarget = new RenderTarget(gl, 1, 1, SCALE_MODES.LINEAR, true);
        this.rootRenderTarget.clearColor = this._backgroundColorRgba;
        this.bindRenderTarget(this.rootRenderTarget);
        this.dispatchEvent('onContextChange');
    };
    WebglRenderer.prototype.render = function (displayObject, renderTexture, transform) {
        //触发onPreRender
        this.dispatchEvent('onPreRender');
        //是否渲染到屏幕root
        this.renderingToScreen = !renderTexture;
        //如果上下文丢失
        if (!this.gl || this.gl.isContextLost()) {
            return;
        }
        if (!renderTexture) {
            this._lastObjectRendered = displayObject;
        }
        //update更新属性
        displayObject.update();
        //更新矩阵
        var cacheParent = displayObject.parent;
        displayObject.parent = this._tempDisplayObjectParent;
        displayObject.updateTransform();
        displayObject.parent = cacheParent;
        //绑定渲染对象，没有则是默认root
        this.bindRenderTexture(renderTexture, transform);
        //当前插件start
        this.batchManager.currentRenderer.start();
        //渲染对象清空画布
        this._activeRenderTarget.clear();
        //开始渲染所有的显示对象
        displayObject.renderWebGL(this);
        //一次性刷一次
        this.batchManager.currentRenderer.flush();
        //回收纹理,回收长时间不用的纹理,从gpu移除,对于很多场景,很多图片的时候很有用,否则gpu容易崩溃
        this.textureGC.update(); //20210601打开注释，忘了为啥之前一直注释
        //触发onPostRender
        this.dispatchEvent('onPostRender');
    };
    /**
     * Erases the active render target and fills the drawing area with a colour
     *
     * @param {number[]} [clearColor] - The colour
     */
    WebglRenderer.prototype.clear = function (clearColor) {
        this._activeRenderTarget.clear(clearColor);
    };
    /**
     * Sets the transform of the active render target to the given matrix
     *
     * @param {Matrix} matrix - The transformation matrix
     */
    WebglRenderer.prototype.setTransform = function (matrix) {
        this._activeRenderTarget.transform = matrix;
    };
    /**
     * Erases the render texture and fills the drawing area with a colour
     *
     * @param {RenderTexture} renderTexture - The render texture to clear
     * @param {number} [clearColor] - The colour
     * @return {WebGLRenderer} Returns itself.
     */
    WebglRenderer.prototype.clearRenderTexture = function (renderTexture, clearColor) {
        var baseTexture = renderTexture.baseTexture;
        var renderTarget = baseTexture._glRenderTargets[this.CONTEXT_UID];
        if (renderTarget) {
            renderTarget.clear(clearColor);
        }
        return this;
    };
    /**
     * Changes the current shader to the one given in parameter
     *
     * @param {Shader} shader - the new shader
     * @param {boolean} [autoProject=true] - Whether automatically set the projection matrix
     * @return {WebGLRenderer} Returns itself.
     */
    WebglRenderer.prototype.bindShader = function (shader, autoProject) {
        if (autoProject === void 0) { autoProject = true; }
        // TODO cache
        if (this._activeShader !== shader) {
            this._activeShader = shader;
            shader.bind();
            // `autoProject` normally would be a default parameter set to true
            // but because of how Babel transpiles default parameters
            // it hinders the performance of this method.
            if (autoProject !== false) {
                // automatically set the projection matrix
                shader.uniforms["projectionMatrix"] = this._activeRenderTarget.projectionMatrix.toArray(true);
            }
        }
        return this;
    };
    /**
     * Creates a new VAO from this renderer's context and state.
     *
     * @return {VertexArrayObject} The new VAO.
     */
    WebglRenderer.prototype.createVao = function () {
        return new VertexArrayObject(this.gl, this.state.attribState);
    };
    /**
     * Changes the current Vao to the one given in parameter
     *
     * @param {VertexArrayObject} vao - the new Vao
     * @return {WebGLRenderer} Returns itself.
     */
    WebglRenderer.prototype.bindVao = function (vao, force) {
        if (force === void 0) { force = false; }
        if (this._activeVao === vao) {
            //计算是同一个也要bind，因为有可能vao里的attr被修改了，但是vao用的同一个，会导致buff不生效
            if (force)
                vao.bind(); //TODO，考虑是否用vao.dirty来确定要不要执行bind（讲道理dirty必须重新bind通道）
            return this;
        }
        if (vao) {
            vao.bind();
        }
        else if (this._activeVao) {
            // TODO this should always be true i think?
            this._activeVao.unbind();
        }
        this._activeVao = vao;
        return this;
    };
    /**
     * Resets the WebGL state so you can render things however you fancy!
     *
     * @return {WebGLRenderer} Returns itself.
     */
    WebglRenderer.prototype.reset = function () {
        this.batchManager.reset();
        this.bindVao(null);
        this._activeShader = null;
        this._activeRenderTarget = this.rootRenderTarget;
        for (var i = 0; i < this.textureManager.boundTextures.length; i++) {
            this.textureManager.boundTextures[i] = this.textureManager.emptyTextures[i];
        }
        // bind the main frame buffer (the screen);
        this.rootRenderTarget.activate();
        this.state.resetToDefault();
        return this;
    };
    /**
     * Binds a render texture for rendering
     *
     * @param {RenderTexture} renderTexture - The render texture to render
     * @param {Matrix} transform - The transform to be applied to the render texture
     * @return {WebGLRenderer} Returns itself.
     */
    WebglRenderer.prototype.bindRenderTexture = function (renderTexture, transform) {
        var renderTarget;
        if (renderTexture) {
            var baseTexture = renderTexture.baseTexture;
            if (!baseTexture._glRenderTargets[this.CONTEXT_UID]) {
                // bind the current texture
                this.textureManager.updateTexture(baseTexture, 0);
            }
            this.textureManager.unbindTexture(baseTexture);
            renderTarget = baseTexture._glRenderTargets[this.CONTEXT_UID];
            renderTarget.setFrame(renderTexture.frame);
        }
        else {
            renderTarget = this.rootRenderTarget;
        }
        renderTarget.transform = transform;
        this.bindRenderTarget(renderTarget);
        return this;
    };
    /**
     * 绑定当前渲染对象
     * @param {RenderTarget} renderTarget - the new render target
     * @return {WebglRenderer} Returns itself.
     */
    WebglRenderer.prototype.bindRenderTarget = function (renderTarget) {
        if (renderTarget !== this._activeRenderTarget) {
            this._activeRenderTarget = renderTarget;
            renderTarget.activate();
            if (this._activeShader) {
                this._activeShader.uniforms.projectionMatrix = renderTarget.projectionMatrix.toArray(true);
            }
            this.stencilManager.setMaskStack(renderTarget.stencilMaskStack);
        }
        return this;
    };
    /**
     * Resizes the webGL view to the specified width and height.
     *
     * @param {number} blendMode - the desired blend mode
     */
    WebglRenderer.prototype.setBlendMode = function (blendMode) {
        this.state.setBlendMode(blendMode);
    };
    /**
     * 传入真实的canvas尺寸
     * @param screenWidth
     * @param screenHeight
     */
    WebglRenderer.prototype.resize = function (screenWidth, screenHeight) {
        _super.prototype.resize.call(this, screenWidth, screenHeight);
        this.rootRenderTarget.resize(screenWidth /** devicePixelRatio*/, screenHeight /** devicePixelRatio*/);
        if (this._activeRenderTarget === this.rootRenderTarget) {
            this.rootRenderTarget.activate();
            if (this._activeShader) {
                this._activeShader.uniforms.projectionMatrix = this.rootRenderTarget.projectionMatrix.toArray(true);
            }
        }
    };
    /**
     * 渲染器销毁方法
     */
    WebglRenderer.prototype.destroy = function () {
        //插件销毁
        this.destroyPlugins();
        // remove listeners，这部分逻辑放舞台里，注意舞台先移除监听，再销毁渲染器
        // this.htmlElement.removeEventListener('webglcontextlost', this.handleContextLost);
        // this.htmlElement.removeEventListener('webglcontextrestored', this.handleContextRestored);
        //纹理管理器销毁
        this.textureManager.destroy();
        //父级销毁方法
        _super.prototype.destroy.call(this);
        // 销毁所有管理器
        this.maskManager.destroy();
        this.stencilManager.destroy();
        this.filterManager.destroy();
        this.maskManager = null;
        this.filterManager = null;
        this.textureManager = null;
        this.handleContextLost = null;
        this.handleContextRestored = null;
        //淘宝小程序内会有问题，这样执行，暂时先注释，如果web环境出问题再修改
        // this.gl.useProgram(null);
        // if (this.gl.getExtension('WEBGL_lose_context')) {
        //   this.gl.getExtension('WEBGL_lose_context').loseContext();
        // }
        // this.gl = null;
    };
    /**
     * webgl上下文恢复时
     * @private
     */
    WebglRenderer.prototype.handleContextRestored = function () {
        this.textureManager.removeAll();
        this.filterManager.destroy(true);
        this._initContext();
        this.resize(this.width, this.height); //放在这吧,改动最小
    };
    /**
     * webgl上下文丢失时
     * @param {WebGLContextEvent} event - 事件
     */
    WebglRenderer.prototype.handleContextLost = function (event) {
        event.preventDefault();
    };
    /**
     * 初始化插件
     * @protected
     * @param {object} staticMap - 静态属性里存的插件列表
     */
    WebglRenderer.prototype.initPlugins = function (staticMap) {
        for (var o in staticMap) {
            this.plugins[o] = new (staticMap[o])(this);
        }
    };
    /**
     * 销毁插件
     */
    WebglRenderer.prototype.destroyPlugins = function () {
        for (var o in this.plugins) {
            this.plugins[o].destroy();
            this.plugins[o] = null;
        }
        this.plugins = null;
    };
    /**
     * 添加插件，用于initPlugins时生成所有插件实例，webgl渲染器估计插件可扩展多，所以加静态方法
     * @method
     * @param {string} pluginName - 插件名，用于区分键值
     * @param {Function} ctor - 插件类
     */
    WebglRenderer.registerPlugin = function (pluginName, ctor) {
        WebglRenderer.__plugins = WebglRenderer.__plugins || {};
        WebglRenderer.__plugins[pluginName] = ctor;
    };
    return WebglRenderer;
}(SystemRenderer));
//注册2d批处理插件，不放这里BatchRenderer文件里，因为不往外引，不会执行，
WebglRenderer.registerPlugin('batch', BatchRenderer);

/**
 * Renderer dedicated to drawing and batching graphics objects.
 *
 * @class
 * @private
 */
var CanvasGraphicsRenderer = /** @class */ (function () {
    /**
     * @param {CanvasRenderer} renderer - The current renderer.
     */
    function CanvasGraphicsRenderer(renderer) {
        this.renderer = renderer;
    }
    /**
     * Renders a Graphics object to a canvas.
     *
     * @param {Graphics} graphics - the actual graphics object to render
     */
    CanvasGraphicsRenderer.prototype.render = function (graphics) {
        var renderer = this.renderer;
        var context = renderer.context;
        var _worldAlpha = graphics._worldAlpha;
        var transform = graphics.transform.worldMatrix;
        context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty);
        //加混色
        renderer.setBlendMode(graphics.blendMode);
        for (var i = 0; i < graphics.graphicsData.length; i++) {
            var data = graphics.graphicsData[i];
            var shape = data.shape;
            var fillStyle = data.fillStyle;
            var lineStyle = data.lineStyle;
            var fillColor = fillStyle.color;
            var lineColor = lineStyle.color;
            context.lineWidth = lineStyle.width;
            //新增3个属性，还有个alignment不晓得应该咋搞好，TODO
            context.lineCap = lineStyle.cap;
            context.lineJoin = lineStyle.join;
            context.miterLimit = lineStyle.miterLimit;
            var ccw = true; //记录画洞的路径方向，填充默认用顺时针，所以画洞用逆时针
            if (data.type === SHAPES.POLY) {
                //必须每次清空子路径列表，因为每个data视为独立
                context.beginPath();
                var points = shape.points;
                context.moveTo(points[0], points[1]);
                for (var m = 1; m < points.length / 2; ++m) {
                    context.lineTo(points[m * 2], points[(m * 2) + 1]);
                }
                ccw = !judgeCcw(points);
            }
            else if (data.type === SHAPES.RECT) {
                if (data.holes.length) {
                    context.beginPath();
                    context.moveTo(shape.x, shape.y);
                    context.lineTo(shape.x + shape.width, shape.y);
                    context.lineTo(shape.x + shape.width, shape.y + shape.height);
                    context.lineTo(shape.x, shape.y + shape.height);
                    context.lineTo(shape.x, shape.y);
                }
                else {
                    //简单处理，直接下一个
                    if (fillStyle.visible) {
                        context.globalAlpha = fillStyle.alpha * _worldAlpha;
                        context.fillStyle = "#" + ("00000" + (fillColor | 0).toString(16)).substr(-6);
                        context.fillRect(shape["x"], shape["y"], shape["width"], shape["height"]);
                    }
                    if (lineStyle.visible) {
                        context.globalAlpha = lineStyle.alpha * _worldAlpha;
                        context.strokeStyle = "#" + ("00000" + (lineColor | 0).toString(16)).substr(-6);
                        context.strokeRect(shape["x"], shape["y"], shape["width"], shape["height"]);
                    }
                    continue;
                }
            }
            else if (data.type === SHAPES.CIRC) {
                //https://www.w3school.com.cn/tags/canvas_arc.asp
                //默认顺时针 counterclockwise= false
                context.beginPath();
                context.arc(shape.x, shape.y, shape.radius, 0, 2 * Math.PI, false);
            }
            else if (data.type === SHAPES.ELIP) {
                // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas
                var w = shape.width * 2;
                var h = shape.height * 2;
                var x = shape.x - (w / 2);
                var y = shape.y - (h / 2);
                context.beginPath();
                var kappa = 0.5522848;
                var ox = (w / 2) * kappa; // control point offset horizontal
                var oy = (h / 2) * kappa; // control point offset vertical
                var xe = x + w; // x-end
                var ye = y + h; // y-end
                var xm = x + (w / 2); // x-middle
                var ym = y + (h / 2); // y-middle
                context.moveTo(x, ym);
                context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
                context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
                context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
                context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
            }
            else if (data.type === SHAPES.RREC) {
                var rx = shape.x;
                var ry = shape.y;
                var width = shape.width;
                var height = shape.height;
                var radius = shape.radius;
                var maxRadius = Math.min(width, height) / 2; //| 0;
                radius = radius > maxRadius ? maxRadius : radius;
                context.beginPath();
                context.moveTo(rx, ry + radius);
                context.quadraticCurveTo(rx, ry, rx + radius, ry);
                context.lineTo(rx + width - radius, ry);
                context.quadraticCurveTo(rx + width, ry, rx + width, ry + radius);
                context.lineTo(rx + width, ry + height - radius);
                context.quadraticCurveTo(rx + width, ry + height, rx + width - radius, ry + height);
                context.lineTo(rx + radius, ry + height);
                context.quadraticCurveTo(rx, ry + height, rx, ry + height - radius);
                context.lineTo(rx, ry + radius);
            }
            //有洞的话，洞的路径需反向,必须闭合，上面一般图形都是顺时针
            for (var j = 0; j < data.holes.length; j++) {
                holePath(data.holes[j], context, ccw);
            }
            if (fillStyle.visible) {
                //fill会闭合路径
                context.globalAlpha = fillStyle.alpha * _worldAlpha;
                context.fillStyle = "#" + ("00000" + (fillColor | 0).toString(16)).substr(-6);
                context.fill();
            }
            if (lineStyle.visible) {
                if (shape.closed)
                    context.closePath();
                context.globalAlpha = lineStyle.alpha * _worldAlpha;
                context.strokeStyle = "#" + ("00000" + (lineColor | 0).toString(16)).substr(-6);
                context.stroke();
            }
        }
    };
    /**
     * destroy graphics object
     *
     */
    CanvasGraphicsRenderer.prototype.destroy = function () {
        this.renderer = null;
    };
    return CanvasGraphicsRenderer;
}());
/**
 * 画洞
 * @param graphicsData
 * @param context
 * @param ccw 逆时针
 */
function holePath(graphicsData, context, ccw) {
    if (ccw === void 0) { ccw = true; }
    var type = graphicsData.type;
    var shape = graphicsData.shape;
    switch (type) {
        case SHAPES.POLY:
            var points = shape.points;
            var hCcw = judgeCcw(points);
            if (ccw == hCcw) {
                context.moveTo(points[0], points[1]);
                for (var m = 1; m < points.length / 2; ++m) {
                    context.lineTo(points[m * 2], points[(m * 2) + 1]);
                }
            }
            else {
                //反序
                context.moveTo(points[points.length - 2], points[points.length - 1]);
                for (var m = points.length / 2 - 2; m >= 0; --m) {
                    context.lineTo(points[m * 2], points[(m * 2) + 1]);
                }
            }
            if (points[0] === points[points.length - 2] && points[1] === points[points.length - 1]) ;
            else {
                context.closePath();
            }
            break;
        case SHAPES.RECT:
            context.moveTo(shape.x, shape.y);
            if (ccw) {
                context.lineTo(shape.x, shape.y + shape.height);
                context.lineTo(shape.x + shape.width, shape.y + shape.height);
                context.lineTo(shape.x + shape.width, shape.y);
                context.lineTo(shape.x, shape.y);
            }
            else {
                context.lineTo(shape.x + shape.width, shape.y);
                context.lineTo(shape.x + shape.width, shape.y + shape.height);
                context.lineTo(shape.x, shape.y + shape.height);
                context.lineTo(shape.x, shape.y);
            }
            break;
        case SHAPES.CIRC:
            context.moveTo(shape.x + shape.radius, shape.y); //得先加这个
            context.arc(shape.x, shape.y, shape.radius, 0, 2 * Math.PI, ccw);
            break;
        case SHAPES.ELIP:
            var w = shape.width * 2;
            var h = shape.height * 2;
            var x = shape.x - (w / 2);
            var y = shape.y - (h / 2);
            var kappa = 0.5522848;
            var ox = (w / 2) * kappa; // control point offset horizontal
            var oy = (h / 2) * kappa; // control point offset vertical
            var xe = x + w; // x-end
            var ye = y + h; // y-end
            var xm = x + (w / 2); // x-middle
            var ym = y + (h / 2); // y-middle
            context.moveTo(x, ym);
            if (ccw) {
                context.bezierCurveTo(xm - ox, ye, x, ym + oy, xm, ye);
                context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xe, ym);
                context.bezierCurveTo(xm + ox, y, xe, ym - oy, xm, y);
                context.bezierCurveTo(x, ym - oy, xm - ox, y, x, ym);
            }
            else {
                context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
                context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
                context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
                context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
            }
            break;
        case SHAPES.RREC:
            var rx = shape.x;
            var ry = shape.y;
            var width = shape.width;
            var height = shape.height;
            var radius = shape.radius;
            var maxRadius = Math.min(width, height) / 2 | 0;
            radius = radius > maxRadius ? maxRadius : radius;
            context.moveTo(rx, ry + radius);
            if (ccw) {
                context.lineTo(rx, ry + height - radius);
                context.quadraticCurveTo(rx, ry + height, rx + radius, ry + height);
                context.lineTo(rx + width - radius, ry + height);
                context.quadraticCurveTo(rx + width, ry + height, rx + width, ry + height - radius);
                context.lineTo(rx + width, ry + radius);
                context.quadraticCurveTo(rx + width, ry, rx + width - radius, ry);
                context.lineTo(rx + radius, ry);
                context.quadraticCurveTo(rx, ry, rx, ry + radius);
            }
            else {
                context.quadraticCurveTo(rx, ry, rx + radius, ry);
                context.lineTo(rx + width - radius, ry);
                context.quadraticCurveTo(rx + width, ry, rx + width, ry + radius);
                context.lineTo(rx + width, ry + height - radius);
                context.quadraticCurveTo(rx + width, ry + height, rx + width - radius, ry + height);
                context.lineTo(rx + radius, ry + height);
                context.quadraticCurveTo(rx, ry + height, rx, ry + height - radius);
                context.lineTo(rx, ry + radius);
            }
            break;
    }
}
/**
 * 判断一组点逆时针还是顺时针
 * @param points 点的一维序列
 * @returns 返回true说明是逆时针ccw，返回false就是顺时针
 */
function judgeCcw(points) {
    var vector = [];
    if (points[0] === points[points.length - 2] && points[1] === points[points.length - 1]) ;
    for (var i = 0; i < points.length - 2; i += 2) {
        vector.push(points[i + 2] - points[i], points[i + 3] - points[i + 1]);
    }
    if (!(points[0] === points[points.length - 2]) || !(points[1] === points[points.length - 1])) {
        //首尾连接
        vector.push(points[0] - points[points.length - 2], points[1] - points[points.length - 1]);
    }
    var sum = 0;
    for (var i = 0; i < vector.length - 2; i += 2) {
        //"x1*y2-y1*x2"
        sum = sum + vector[i] * vector[i + 3] - vector[i + 1] * vector[i + 2];
    }
    sum = sum + vector[vector.length - 2] * vector[1] - vector[vector.length - 1] * vector[0];
    //坑爹啊，2D的以左上角为原点，左x正，下y正，取个反
    return !(sum > 0);
}

/**
 *
 */
var CanvasMaskManager = /** @class */ (function (_super) {
    __extends(CanvasMaskManager, _super);
    /**
     * @param {CanvasRenderer} renderer - The canvas renderer.
     */
    function CanvasMaskManager(renderer) {
        var _this = _super.call(this) || this;
        _this._instanceType = "CanvasMaskManager";
        _this.renderer = renderer;
        return _this;
    }
    /**
     * This method adds it to the current stack of masks.
     *
     * @param {object} maskData - the maskData that will be pushed
     */
    CanvasMaskManager.prototype.pushMask = function (maskData) {
        var renderer = this.renderer;
        renderer.context.save();
        renderer.context.globalAlpha = 0; //得加上，不绘制
        var transform = maskData.transform.worldMatrix;
        renderer.context.setTransform(transform.a || 0.0000000001, //暂时发现a或d为0时，接下来绘制被遮对象用的setTransform时遮罩clip不起作用
        transform.b, transform.c, transform.d || 0.0000000001, transform.tx, transform.ty);
        //兼容下canvas下也能用Shape作为遮罩
        if (maskData.instanceType == "Shape") {
            maskData["_drawShape"](renderer.context);
        }
        else if (maskData.instanceType == "Graphics") { //还有那种sprite的。。。暂时这么判断，canvas下的sprite无效
            //以防万一，没有end，加一段，不考虑闭合情况
            maskData["finishPoly"]();
            this.renderGraphicsShape(maskData);
        }
        renderer.context.clip();
    };
    /**
     * Renders a Graphics shape.
     *
     * @param {Graphics} graphics - The object to render.
     */
    CanvasMaskManager.prototype.renderGraphicsShape = function (graphics) {
        var context = this.renderer.context;
        var len = graphics.graphicsData.length;
        if (len === 0)
            return;
        //beginPath 清空子路径列表
        //clip和fill都会把当beginPath后的所有的子路径进行裁剪或填充，且闭合当前子路径，但是不会清空子路径列表
        //stroke不会闭合当前子路径
        //closePath闭合当前子路径，和beginPath并不对应，手动将首尾闭合就没必要调用closePath
        //rect，arc都是顺时针的，rect会首尾闭合，arc全角也会闭合
        //几个都要应用的话，只执行一次beginPath  
        context.beginPath();
        for (var i = 0; i < len; i++) {
            var data = graphics.graphicsData[i];
            var shape = data.shape;
            var ccw = true;
            if (data.type === SHAPES.POLY) {
                var points = shape.points;
                context.moveTo(points[0], points[1]);
                for (var j = 1; j < points.length / 2; j++) {
                    context.lineTo(points[j * 2], points[(j * 2) + 1]);
                }
                ccw = !judgeCcw(points);
                // if the first and last point are the same close the path - much neater :)
                if (points[0] === points[points.length - 2] && points[1] === points[points.length - 1]) ;
                else {
                    context.closePath();
                }
            }
            else if (data.type === SHAPES.RECT) {
                context.rect(shape.x, shape.y, shape.width, shape.height);
            }
            else if (data.type === SHAPES.CIRC) {
                // TODO - need to be Undefined!
                context.arc(shape.x, shape.y, shape.radius, 0, 2 * Math.PI);
            }
            else if (data.type === SHAPES.ELIP) {
                // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas
                var w = shape.width * 2;
                var h = shape.height * 2;
                var x = shape.x - (w / 2);
                var y = shape.y - (h / 2);
                var kappa = 0.5522848;
                var ox = (w / 2) * kappa; // control point offset horizontal
                var oy = (h / 2) * kappa; // control point offset vertical
                var xe = x + w; // x-end
                var ye = y + h; // y-end
                var xm = x + (w / 2); // x-middle
                var ym = y + (h / 2); // y-middle
                context.moveTo(x, ym);
                context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
                context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
                context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
                context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
            }
            else if (data.type === SHAPES.RREC) {
                var rx = shape.x;
                var ry = shape.y;
                var width = shape.width;
                var height = shape.height;
                var radius = shape.radius;
                var maxRadius = Math.min(width, height) / 2 | 0;
                radius = radius > maxRadius ? maxRadius : radius;
                context.moveTo(rx, ry + radius);
                context.quadraticCurveTo(rx, ry, rx + radius, ry);
                context.lineTo(rx + width - radius, ry);
                context.quadraticCurveTo(rx + width, ry, rx + width, ry + radius);
                context.lineTo(rx + width, ry + height - radius);
                context.quadraticCurveTo(rx + width, ry + height, rx + width - radius, ry + height);
                context.lineTo(rx + radius, ry + height);
                context.quadraticCurveTo(rx, ry + height, rx, ry + height - radius);
                context.lineTo(rx, ry + radius);
            }
            for (var j = 0; j < data.holes.length; j++) {
                holePath(data.holes[i], context, ccw);
            }
        }
    };
    /**
     * Restores the current drawing context to the state it was before the mask was applied.
     *
     * @param {CanvasRenderer} renderer - The renderer context to use.
     */
    CanvasMaskManager.prototype.popMask = function (renderer) {
        renderer.context.restore();
    };
    /**
     * Destroys this canvas mask manager.
     *
     */
    CanvasMaskManager.prototype.destroy = function () {
        /* empty */
    };
    return CanvasMaskManager;
}(HashObject));

var result = null;
/**
 * 创建带颜色的canvas
 * @ignore
 * @param {string} color - The color to make the canvas
 * @return {canvas} a small canvas element
 */
function createColoredCanvas(color) {
    var canvas = createCanvas(); //document.createElement('canvas');
    canvas.width = 6;
    canvas.height = 1;
    var context = canvas.getContext('2d');
    context.fillStyle = color;
    context.fillRect(0, 0, 6, 1);
    return canvas;
}
/**
 * 检查当前浏览器的canvas是否可用blendMode
 * @return {boolean} 为true表示可用
 */
function canUseNewCanvasBlendModes() {
    //检查过了
    if (result != null)
        return result;
    //document都没有
    if (typeof document === 'undefined') {
        result = false;
        return result;
    }
    var magenta = createColoredCanvas('#ff00ff');
    var yellow = createColoredCanvas('#ffff00');
    var canvas = createCanvas(); //document.createElement('canvas');
    canvas.width = 6;
    canvas.height = 1;
    var context = canvas.getContext('2d');
    context.globalCompositeOperation = 'multiply';
    context.drawImage(magenta, 0, 0);
    context.drawImage(yellow, 2, 0);
    var imageData = context.getImageData(2, 0, 1, 1);
    if (!imageData) {
        result = false;
        return result;
    }
    var data = imageData.data;
    result = (data[0] === 255 && data[1] === 0 && data[2] === 0);
    return result;
}

/**
 * Number of steps which will be used as a cap when rounding colors.
 *
 * @type {number}
 */
var cacheStepsPerColorChannel = 8;
/**
 * 做缓存使用，若不转换为Image，一般不用
 */
var defaultCanvas;
/**
 * 调色方法，根据混色是否可用
 */
var tintMethod; //= canUseNewCanvasBlendModes() ? tintWithMultiply : tintWithPerPixel;
/**
 * Basically this method just needs a sprite and a color and tints the sprite with the given color.
 *
 * @param {Texture} texture - the sprite to tint
 * @param {number} color - the color to use to tint the sprite with
 * @return {HTMLCanvasElement} The tinted canvas
 */
function getTintedTexture(texture, color) {
    color = roundColor(color);
    var stringColor = "#" + ("00000" + (color | 0).toString(16)).substr(-6);
    texture["tintCache"] = texture["tintCache"] || {};
    var cachedTexture = texture["tintCache"][stringColor];
    var canvas;
    if (cachedTexture) {
        if (cachedTexture.tintId === texture._updateID) {
            return texture["tintCache"][stringColor];
        }
        canvas = texture["tintCache"][stringColor];
    }
    else {
        canvas = defaultCanvas || createCanvas(); //document.createElement('canvas');
    }
    //用到时才执行
    if (!tintMethod)
        tintMethod = canUseNewCanvasBlendModes() ? tintWithMultiply : tintWithPerPixel;
    tintMethod(texture, color, canvas);
    canvas.tintId = texture._updateID;
    {
        texture["tintCache"][stringColor] = canvas;
        // if we are not converting the texture to an image then we need to lose the reference to the canvas
        defaultCanvas = null;
    }
    return canvas;
}
/**
 * Tint a texture using the 'multiply' operation.
 * @param {Texture} texture - the texture to tint
 * @param {number} color - the color to use to tint the sprite with
 * @param {HTMLCanvasElement} canvas - the current canvas
 */
function tintWithMultiply(texture, color, canvas) {
    var context = canvas.getContext('2d');
    var crop = texture._frame.clone();
    canvas.width = Math.ceil(crop.width);
    canvas.height = Math.ceil(crop.height);
    context.save();
    context.fillStyle = "#" + ("00000" + (color | 0).toString(16)).substr(-6);
    context.fillRect(0, 0, crop.width, crop.height);
    context.globalCompositeOperation = 'multiply';
    context.drawImage(texture.baseTexture.source, crop.x, crop.y, crop.width, crop.height, 0, 0, crop.width, crop.height);
    context.globalCompositeOperation = 'destination-atop';
    context.drawImage(texture.baseTexture.source, crop.x, crop.y, crop.width, crop.height, 0, 0, crop.width, crop.height);
    context.restore();
}
/**
 * Tint a texture pixel per pixel.
 *
 * @param {Texture} texture - the texture to tint
 * @param {number} color - the color to use to tint the sprite with
 * @param {HTMLCanvasElement} canvas - the current canvas
 */
function tintWithPerPixel(texture, color, canvas) {
    var context = canvas.getContext('2d');
    var crop = texture._frame.clone();
    canvas.width = Math.ceil(crop.width);
    canvas.height = Math.ceil(crop.height);
    context.save();
    context.globalCompositeOperation = 'copy';
    context.drawImage(texture.baseTexture.source, crop.x, crop.y, crop.width, crop.height, 0, 0, crop.width, crop.height);
    context.restore();
    var rgbValues = hex2rgb(color);
    var r = rgbValues[0];
    var g = rgbValues[1];
    var b = rgbValues[2];
    var pixelData = context.getImageData(0, 0, crop.width, crop.height);
    var pixels = pixelData.data;
    for (var i = 0; i < pixels.length; i += 4) {
        pixels[i + 0] *= r;
        pixels[i + 1] *= g;
        pixels[i + 2] *= b;
    }
    context.putImageData(pixelData, 0, 0);
}
function rgb2hex(rgb) {
    return (((rgb[0] * 255) << 16) + ((rgb[1] * 255) << 8) + (rgb[2] * 255 | 0));
}
function hex2rgb(hex, out) {
    out = out || [];
    out[0] = ((hex >> 16) & 0xFF) / 255;
    out[1] = ((hex >> 8) & 0xFF) / 255;
    out[2] = (hex & 0xFF) / 255;
    return out;
}
function roundColor(color) {
    var step = cacheStepsPerColorChannel;
    var rgbValues = hex2rgb(color);
    rgbValues[0] = Math.min(255, (rgbValues[0] / step) * step);
    rgbValues[1] = Math.min(255, (rgbValues[1] / step) * step);
    rgbValues[2] = Math.min(255, (rgbValues[2] / step) * step);
    return rgb2hex(rgbValues);
}

var canvasRenderWorldTransform = new Matrix();
/**
 * Renderer dedicated to drawing and batching sprites.
 *
 * @class
 * @private
 */
var CanvasSpriteRenderer = /** @class */ (function () {
    /**
     * @param {CanvasRenderer} renderer -The renderer sprite this batch works for.
     */
    function CanvasSpriteRenderer(renderer) {
        this.renderer = renderer;
    }
    /**
     * Renders the sprite object.
     * 渲染带texture的显示对象，Sprite,Graphic
     * @param {Sprite} sprite - the sprite to render when using this spritebatch
     */
    CanvasSpriteRenderer.prototype.render = function (sprite) {
        var texture = sprite._texture;
        var renderer = this.renderer;
        var width = texture._frame.width;
        var height = texture._frame.height;
        var wt = sprite.transform.worldMatrix;
        var dx = 0;
        var dy = 0;
        if (texture.orig.width <= 0 || texture.orig.height <= 0 || !texture.baseTexture.source)
            return;
        //  Ignore null sources
        if (!texture.valid)
            return;
        //设置混色模式
        renderer.setBlendMode(sprite.blendMode);
        //透明度
        renderer.context.globalAlpha = sprite._worldAlpha;
        // If smoothingEnabled is supported and we need to change the smoothing property for sprite texture
        // const smoothingEnabled = texture.baseTexture.scaleMode === SCALE_MODES.LINEAR;
        // if (renderer.smoothProperty && renderer.context[renderer.smoothProperty] !== smoothingEnabled) {
        //     // 如果遇到性能问题，先禁掉
        //     renderer.context[renderer.smoothProperty] = smoothingEnabled;
        // }
        if (sprite._anchorTexture) { //sprite
            if (texture.trim) {
                dx = (texture.trim.width / 2) + texture.trim.x - (sprite._anchorTexture.x * texture.orig.width);
                dy = (texture.trim.height / 2) + texture.trim.y - (sprite._anchorTexture.y * texture.orig.height);
            }
            else {
                dx = (0.5 - sprite._anchorTexture.x) * texture.orig.width;
                dy = (0.5 - sprite._anchorTexture.y) * texture.orig.height;
            }
            if (texture.rotate) {
                canvasRenderWorldTransform.copy(wt);
                wt = canvasRenderWorldTransform;
                GroupD8.matrixAppendRotationInv(wt, texture.rotate, dx, dy);
                // the anchor has already been applied above, so lets set it to zero
                dx = 0;
                dy = 0;
            }
            dx -= width / 2;
            dy -= height / 2;
        }
        else if (sprite.instanceType == "Graphics") { //graphics
            // dx = sprite["offsetX"] || 0;
            // dy = sprite["offsetY"] || 0;
            // console.log(sprite["offsetX"])
            //不用offset或_offset,在Graphics里删除了，直接用_localBoundsSelf
            var _a = sprite._localBoundsSelf, x = _a.x, y = _a.y;
            dx = x;
            dy = y;
        }
        renderer.context.setTransform(wt.a, wt.b, wt.c, wt.d, wt.tx, wt.ty);
        //处理outerBlend
        var outerBlend = renderer._outerBlend;
        if (outerBlend) {
            renderer.context.save();
            renderer.context.beginPath();
            renderer.context.rect(dx, dy, width, height);
            renderer.context.clip();
        }
        //判断调色
        if (sprite.tint !== 0xFFFFFF) {
            if (sprite.cachedTint !== sprite.tint || sprite.tintedTexture.tintId !== sprite._texture._updateID) {
                sprite.cachedTint = sprite.tint;
                //在sprite的destroy里置空，_texture上的tintCache暂时没法清
                sprite.tintedTexture = getTintedTexture(sprite._texture, sprite.tint);
            }
            renderer.context.drawImage(sprite.tintedTexture, 0, 0, width, height, dx, dy, width, height);
        }
        else {
            //考虑是否分开，
            renderer.context.drawImage(texture.baseTexture.source, //不支持data类型
            texture._frame.x, texture._frame.y, width, height, dx, dy, width, height);
        }
        //如果处理过outerBlend
        if (outerBlend)
            renderer.context.restore();
        //以防万一，设置一次
        renderer.setBlendMode(BLEND_MODES.NORMAL);
    };
    /**
     * destroy the sprite object.
     *
     */
    CanvasSpriteRenderer.prototype.destroy = function () {
        this.renderer = null;
    };
    return CanvasSpriteRenderer;
}());

/**
 * Creates a Canvas element of the given size.
 * 其实就是一个离屏canvas，webgl模式不需要建canvas，因为可以用帧缓存
 */
var CanvasRenderTarget = /** @class */ (function () {
    /**
     * @param {number} width - the width for the newly created canvas
     * @param {number} height - the height for the newly created canvas
     */
    function CanvasRenderTarget(width, height) {
        this.canvas = createCanvas(); //document.createElement('canvas');
        // console.log("rd1",this.canvas)
        this.resize(width, height); //要先设置尺寸？
        this.context = this.canvas.getContext('2d');
        // console.log("rd",this.context)
        this.resize(width, height); //为何要多加一次
        this.clear(); //淘宝canvas问题，绘制前必须调用过clearRect，否则就有几率绘制不出来
    }
    /**
     * Clears the canvas that was created by the CanvasRenderTarget class.
     *
     * @private
     */
    CanvasRenderTarget.prototype.clear = function () {
        this.context.setTransform(1, 0, 0, 1, 0, 0);
        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
    };
    /**
     * Resizes the canvas to the specified width and height.
     *
     * @param {number} width - the new width of the canvas
     * @param {number} height - the new height of the canvas
     */
    CanvasRenderTarget.prototype.resize = function (width, height) {
        this.canvas.width = width;
        this.canvas.height = height;
    };
    /**
     * Destroys this canvas.
     *
     */
    CanvasRenderTarget.prototype.destroy = function () {
        this.context = null;
        this.canvas = null;
    };
    Object.defineProperty(CanvasRenderTarget.prototype, "width", {
        /**
         * The width of the canvas buffer in pixels.
         *
         * @member {number}
         */
        get: function () {
            return this.canvas.width;
        },
        set: function (val) {
            this.canvas.width = val;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(CanvasRenderTarget.prototype, "height", {
        /**
         * The height of the canvas buffer in pixels.
         *
         * @member {number}
         */
        get: function () {
            return this.canvas.height;
        },
        set: function (val) {
            this.canvas.height = val;
        },
        enumerable: false,
        configurable: true
    });
    return CanvasRenderTarget;
}());

/**
 * canvas模式下网格渲染插件
 */
var CanvasMeshRenderer = /** @class */ (function () {
    function CanvasMeshRenderer(renderer) {
        this.renderer = renderer;
    }
    CanvasMeshRenderer.prototype.render = function (mesh) {
        var renderer = this.renderer;
        var context = renderer.context;
        var transform = mesh.worldMatrix;
        context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty);
        renderer.context.globalAlpha = mesh._worldAlpha;
        renderer.setBlendMode(mesh.blendMode);
        //当没有纹理,纯色的时候,可以用其他方式渲染,到时再说
        this._renderTriangles(mesh);
    };
    CanvasMeshRenderer.prototype._renderTriangles = function (mesh) {
        var indices = mesh._indices;
        var length = indices.length;
        for (var i = 0; i < length; i += 3) {
            var index0 = indices[i] * 2;
            var index1 = indices[i + 1] * 2;
            var index2 = indices[i + 2] * 2;
            this._renderDrawTriangle(mesh, index0, index1, index2);
        }
    };
    CanvasMeshRenderer.prototype._renderDrawTriangle = function (mesh, index0, index1, index2) {
        var context = this.renderer.context;
        var uvs = mesh._uvs;
        var vertices = mesh._vertices;
        var texture = mesh.texture;
        if (!texture.valid)
            return;
        var base = texture.baseTexture;
        var textureSource = base.source;
        var textureWidth = base.width;
        var textureHeight = base.height;
        var u0 = uvs[index0] * base.width;
        var u1 = uvs[index1] * base.width;
        var u2 = uvs[index2] * base.width;
        var v0 = uvs[index0 + 1] * base.height;
        var v1 = uvs[index1 + 1] * base.height;
        var v2 = uvs[index2 + 1] * base.height;
        var x0 = vertices[index0];
        var x1 = vertices[index1];
        var x2 = vertices[index2];
        var y0 = vertices[index0 + 1];
        var y1 = vertices[index1 + 1];
        var y2 = vertices[index2 + 1];
        var canvasPadding = mesh.canvasPadding;
        if (canvasPadding > 0) {
            var paddingX = canvasPadding / Math.abs(mesh.worldMatrix.a);
            var paddingY = canvasPadding / Math.abs(mesh.worldMatrix.d);
            var centerX = (x0 + x1 + x2) / 3;
            var centerY = (y0 + y1 + y2) / 3;
            var normX = x0 - centerX;
            var normY = y0 - centerY;
            var dist = Math.sqrt((normX * normX) + (normY * normY));
            x0 = centerX + ((normX / dist) * (dist + paddingX));
            y0 = centerY + ((normY / dist) * (dist + paddingY));
            //
            normX = x1 - centerX;
            normY = y1 - centerY;
            dist = Math.sqrt((normX * normX) + (normY * normY));
            x1 = centerX + ((normX / dist) * (dist + paddingX));
            y1 = centerY + ((normY / dist) * (dist + paddingY));
            normX = x2 - centerX;
            normY = y2 - centerY;
            dist = Math.sqrt((normX * normX) + (normY * normY));
            x2 = centerX + ((normX / dist) * (dist + paddingX));
            y2 = centerY + ((normY / dist) * (dist + paddingY));
        }
        //设定截取三角面的路径
        context.save();
        context.beginPath();
        context.moveTo(x0, y0);
        context.lineTo(x1, y1);
        context.lineTo(x2, y2);
        context.closePath();
        context.clip();
        // Compute matrix transform
        var delta = (u0 * v1) + (v0 * u2) + (u1 * v2) - (v1 * u2) - (v0 * u1) - (u0 * v2);
        var deltaA = (x0 * v1) + (v0 * x2) + (x1 * v2) - (v1 * x2) - (v0 * x1) - (x0 * v2);
        var deltaB = (u0 * x1) + (x0 * u2) + (u1 * x2) - (x1 * u2) - (x0 * u1) - (u0 * x2);
        var deltaC = (u0 * v1 * x2) + (v0 * x1 * u2) + (x0 * u1 * v2) - (x0 * v1 * u2) - (v0 * u1 * x2) - (u0 * x1 * v2);
        var deltaD = (y0 * v1) + (v0 * y2) + (y1 * v2) - (v1 * y2) - (v0 * y1) - (y0 * v2);
        var deltaE = (u0 * y1) + (y0 * u2) + (u1 * y2) - (y1 * u2) - (y0 * u1) - (u0 * y2);
        var deltaF = (u0 * v1 * y2) + (v0 * y1 * u2) + (y0 * u1 * v2) - (y0 * v1 * u2) - (v0 * u1 * y2) - (u0 * y1 * v2);
        context.transform(deltaA / delta, deltaD / delta, deltaB / delta, deltaE / delta, deltaC / delta, deltaF / delta);
        context.drawImage(textureSource, 0, 0, textureWidth, textureHeight, 0, 0, textureWidth, textureHeight);
        context.restore();
    };
    // renderMeshFlat(mesh) {
    //     const context = this.renderer.context;
    //     const vertices = mesh.vertices;
    //     const length = vertices.length / 2;
    //     // this.count++;
    //     context.beginPath();
    //     for (let i = 1; i < length - 2; ++i) {
    //         // draw some triangles!
    //         const index = i * 2;
    //         const x0 = vertices[index];
    //         const y0 = vertices[index + 1];
    //         const x1 = vertices[index + 2];
    //         const y1 = vertices[index + 3];
    //         const x2 = vertices[index + 4];
    //         const y2 = vertices[index + 5];
    //         context.moveTo(x0, y0);
    //         context.lineTo(x1, y1);
    //         context.lineTo(x2, y2);
    //     }
    //     context.fillStyle = '#FF0000';
    //     context.fill();
    //     context.closePath();
    // }
    CanvasMeshRenderer.prototype.destroy = function () {
        this.renderer = null;
    };
    return CanvasMeshRenderer;
}());

function mapCanvasBlendModes(array) {
    if (array === void 0) { array = []; }
    if (canUseNewCanvasBlendModes()) {
        array[BLEND_MODES.NORMAL] = 'source-over';
        array[BLEND_MODES.ADD] = 'lighter'; // IS THIS OK???
        array[BLEND_MODES.MULTIPLY] = 'multiply';
        array[BLEND_MODES.SCREEN] = 'screen';
        array[BLEND_MODES.OVERLAY] = 'overlay';
        array[BLEND_MODES.DARKEN] = 'darken';
        array[BLEND_MODES.LIGHTEN] = 'lighten';
        array[BLEND_MODES.COLOR_DODGE] = 'color-dodge';
        array[BLEND_MODES.COLOR_BURN] = 'color-burn';
        array[BLEND_MODES.HARD_LIGHT] = 'hard-light';
        array[BLEND_MODES.SOFT_LIGHT] = 'soft-light';
        array[BLEND_MODES.DIFFERENCE] = 'difference';
        array[BLEND_MODES.EXCLUSION] = 'exclusion';
        array[BLEND_MODES.HUE] = 'hue';
        array[BLEND_MODES.SATURATION] = 'saturate';
        array[BLEND_MODES.COLOR] = 'color';
        array[BLEND_MODES.LUMINOSITY] = 'luminosity';
    }
    else {
        // this means that the browser does not support the cool new blend modes in canvas 'cough' ie 'cough'
        array[BLEND_MODES.NORMAL] = 'source-over';
        array[BLEND_MODES.ADD] = 'lighter'; // IS THIS OK???
        array[BLEND_MODES.MULTIPLY] = 'source-over';
        array[BLEND_MODES.SCREEN] = 'source-over';
        array[BLEND_MODES.OVERLAY] = 'source-over';
        array[BLEND_MODES.DARKEN] = 'source-over';
        array[BLEND_MODES.LIGHTEN] = 'source-over';
        array[BLEND_MODES.COLOR_DODGE] = 'source-over';
        array[BLEND_MODES.COLOR_BURN] = 'source-over';
        array[BLEND_MODES.HARD_LIGHT] = 'source-over';
        array[BLEND_MODES.SOFT_LIGHT] = 'source-over';
        array[BLEND_MODES.DIFFERENCE] = 'source-over';
        array[BLEND_MODES.EXCLUSION] = 'source-over';
        array[BLEND_MODES.HUE] = 'source-over';
        array[BLEND_MODES.SATURATION] = 'source-over';
        array[BLEND_MODES.COLOR] = 'source-over';
        array[BLEND_MODES.LUMINOSITY] = 'source-over';
    }
    // not-premultiplied, only for webgl
    array[BLEND_MODES.NORMAL_NPM] = array[BLEND_MODES.NORMAL];
    array[BLEND_MODES.ADD_NPM] = array[BLEND_MODES.ADD];
    array[BLEND_MODES.SCREEN_NPM] = array[BLEND_MODES.SCREEN];
    //和NORMAL一致
    array[BLEND_MODES.SRC_OVER] = 'source-over';
    // composite operations
    array[BLEND_MODES.SRC_IN] = 'source-in';
    array[BLEND_MODES.SRC_OUT] = 'source-out';
    array[BLEND_MODES.SRC_ATOP] = 'source-atop';
    array[BLEND_MODES.DST_OVER] = 'destination-over';
    array[BLEND_MODES.DST_IN] = 'destination-in';
    array[BLEND_MODES.DST_OUT] = 'destination-out';
    array[BLEND_MODES.DST_ATOP] = 'destination-atop';
    // SUBTRACT from flash, does not exist in canvas
    array[BLEND_MODES.SUBTRACT] = 'source-over';
    return array;
}

/**
 * 暂时不用，用时再说
 */
var CanvasRenderer = /** @class */ (function (_super) {
    __extends(CanvasRenderer, _super);
    function CanvasRenderer(context, width, height) {
        var _this = _super.call(this) || this;
        _this.type = RENDERER_TYPE.CANVAS;
        _this._instanceType = "CanvasRenderer";
        _this.rootContext = context;
        _this.maskManager = new CanvasMaskManager(_this);
        // this.initPlugins();
        _this.plugins = {
            sprite: new CanvasSpriteRenderer(_this),
            graphics: new CanvasGraphicsRenderer(_this),
            mesh: new CanvasMeshRenderer(_this)
        };
        _this.blendModes = mapCanvasBlendModes();
        _this._activeBlendMode = null;
        _this._outerBlend = false;
        //
        _this.resize(width, height);
        return _this;
    }
    /**
     * 渲染方法
     * @param {DisplayObject} displayObject - 渲染对象
     * @param {RenderTexture} [renderTexture] -离屏渲染纹理
     * @param {Matrix} [transform] - 矩阵偏移
     */
    CanvasRenderer.prototype.render = function (displayObject, renderTexture /*RenderTexture*/, transform) {
        //渲染开始前触发
        this.dispatchEvent('onPreRender');
        //是否渲染到主屏幕
        var renderingToScreen = !renderTexture;
        if (renderTexture) {
            renderTexture = renderTexture.baseTexture || renderTexture;
            if (!renderTexture._canvasRenderTarget) {
                renderTexture._canvasRenderTarget = new CanvasRenderTarget(renderTexture.width, renderTexture.height);
                renderTexture.source = renderTexture._canvasRenderTarget.canvas;
                renderTexture.valid = true;
            }
            else {
                //已有的话，需要重画
                renderTexture._canvasRenderTarget.clear();
                renderTexture._canvasRenderTarget.resize(renderTexture.width, renderTexture.height);
            }
            //当前上下文要修改成离屏的
            this.context = renderTexture._canvasRenderTarget.context;
        }
        else {
            //当前上下文就是根节点的
            this.context = this.rootContext;
        }
        var context = this.context;
        if (!renderTexture) {
            this._lastObjectRendered = displayObject;
        }
        //update更新属性
        displayObject.update();
        //存下真实的父级对象
        var cacheParent = displayObject.parent;
        var tempWt = this._tempDisplayObjectParent.transform.worldMatrix;
        if (transform) {
            //有transform则复制
            tempWt.copy(transform);
            //标记要更新transform，确保子级会更新全局矩阵，（改成++）TODO待测试，Graphics和截图两个地方用到了transform
            this._tempDisplayObjectParent.transform._worldID++;
        }
        else {
            //没有就初始化
            tempWt.identity();
        }
        displayObject.parent = this._tempDisplayObjectParent;
        displayObject.updateTransform();
        displayObject.parent = cacheParent;
        //初始化上下文状态
        context.save();
        context.setTransform(1, 0, 0, 1, 0, 0);
        context.globalAlpha = 1;
        //默认模式
        this._activeBlendMode = BLEND_MODES.NORMAL;
        this._outerBlend = false;
        context.globalCompositeOperation = this.blendModes[BLEND_MODES.NORMAL];
        // context.clearRect(0, 0, this.width, this.height);
        if (renderingToScreen) {
            if (this.transparent) {
                context.clearRect(0, 0, this.width, this.height);
            }
            else {
                context.fillStyle = this._backgroundColorString;
                context.fillRect(0, 0, this.width, this.height);
            }
        }
        //执行绘制
        displayObject.renderCanvas(this);
        // context["draw"]();
        context.restore();
        //渲染后触发
        this.dispatchEvent('onPostRender');
    };
    /**
     * 设置混色模式
     * @param {number} blendMode
     * @param {boolean} [readyForOuterBlend=false] 部分混色会改变渲染边缘,所以是否要改变得确定传值,默认false,这些混色方式当作normal处理
     */
    CanvasRenderer.prototype.setBlendMode = function (blendMode, readyForOuterBlend) {
        if (readyForOuterBlend === void 0) { readyForOuterBlend = false; }
        var outerBlend = blendMode === BLEND_MODES.SRC_IN
            || blendMode === BLEND_MODES.SRC_OUT
            || blendMode === BLEND_MODES.DST_IN
            || blendMode === BLEND_MODES.DST_ATOP;
        if (!readyForOuterBlend && outerBlend) {
            blendMode = BLEND_MODES.NORMAL;
        }
        if (this._activeBlendMode === blendMode) {
            return;
        }
        this._activeBlendMode = blendMode;
        this._outerBlend = outerBlend;
        this.context.globalCompositeOperation = this.blendModes[blendMode];
    };
    /**
     * 销毁
     */
    CanvasRenderer.prototype.destroy = function () {
        this.destroyPlugins();
        _super.prototype.destroy.call(this);
        this.context = null;
        this.maskManager.destroy();
        this.maskManager = null;
    };
    CanvasRenderer.prototype.destroyPlugins = function () {
        this.plugins.sprite.destroy();
        this.plugins.graphics.destroy();
        this.plugins.mesh.destroy();
    };
    return CanvasRenderer;
}(SystemRenderer));

var Stage = /** @class */ (function (_super) {
    __extends(Stage, _super);
    /**
     * 建立舞台
     * 注意淘宝小程序canvas实际宽高/显示宽高必须是dpr，要么传dpr（参数resolution），要么外部自行设置实际宽高（canvas.width）及显示宽高（样式）
     * @param canvas canvas标签
     * @param desWidth 舞台设计宽，为了直接在舞台加东西不需要考虑缩放
     * @param desHeight 舞台设计高，为了直接在舞台加东西不需要考虑缩放
     * @param divWidth canvas显示宽，或视图宽度，或样式宽度，全屏就是屏幕宽度document.body.clientWidth(web环境)或my.getSystemInfoSync().windowWidth(淘宝小程序)
     * @param divHeight canvas显示高，或视图高度，或样式高度，全屏就是屏幕宽度document.body.clientHeight(web环境)或my.getSystemInfoSync().windowHeight(淘宝小程序)
     * @param renderType 渲染类型,默认canvas
     * @param stageCenter 舞台是否根据设计尺寸居中,默认false(左上角置顶)
     * @param fixedHeight 是否定高,默认false(定宽)
     * @param resolution 分辨率，一般传设备的devicePixelRatio，不传意味着外部自行处理了canvas的实际宽高及显示宽高（注意淘宝小程序实际宽高/显示宽高必须是dpr，要么传dpr，要么外部设置）
     * @param webglOptions 获取webgl上下文时需要的参数，一般用默认的，默认alpha:true,antialias:false,premultipliedAlpha:true,stencil:true,preserveDrawingBuffer:false
     */
    function Stage(canvas, desWidth, desHeight, divWidth, divHeight, renderType, stageCenter, fixedHeight, resolution, webglOptions) {
        if (desWidth === void 0) { desWidth = 750; }
        if (desHeight === void 0) { desHeight = 1624; }
        if (renderType === void 0) { renderType = RENDERER_TYPE.CANVAS; }
        if (stageCenter === void 0) { stageCenter = false; }
        if (fixedHeight === void 0) { fixedHeight = false; }
        var _this = _super.call(this) || this;
        /**
         * stage使用的渲染器
         * @property renderObj
         * @public
         * @since 1.0.0
         * @type {SystemRenderer}
         * @default null
         */
        _this.renderObj = null;
        /**
         * 舞台在设备里截取后的可见区域,有些时候知道可见区域是非常重要的,因为这样你就可以根据舞台的可见区域做自适应了。
         * @property viewRect
         * @public
         * @since 1.0.0
         * @type {Rectangle}
         * @default
         * @readonly
         */
        _this.viewRect = new Rectangle();
        /**
         * 舞台设计尺寸，一般为设计稿内容尺寸
         * @property desWidth
         * @public
         * @since 1.0.0
         * @default 0
         * @type {number}
         * @readonly
         */
        _this.desWidth = 0;
        /**
         * 舞台设计尺寸，一般为设计稿内容尺寸
         * @property desHeight
         * @public
         * @since 1.0.0
         * @default 0
         * @type {number}
         * @readonly
         */
        _this.desHeight = 0;
        /**
         * 舞台在设备中的显示尺寸
         * @property divHeight
         * @public
         * @since 1.0.0
         * @default 0
         * @type {number}
         * @readonly
         */
        _this.divHeight = 0;
        /**
         * 舞台在设备中的显示尺寸
         * @property divWidth
         * @public
         * @since 1.0.0
         * @default 0
         * @readonly
         * @type {number}
         */
        _this.divWidth = 0;
        _this._bgColor = 0x000000;
        /**
         * 上一次鼠标或触碰经过的显示对象列表，为了over和out事件
         * @property _lastDpList
         * @type {Object}
         * @private
         */
        _this._lastDpList = {};
        /**
         * 淘宝小程序环境canvas的偏移,淘宝环境才用,web环境实时,字段保留,但是不会计算了
         */
        _this.canvasOffsetTb = { x: 0, y: 0 };
        _this._autoSteering = false;
        /**
         * 鼠标事件MouseEvent对象池
         * @property _ml
         * @type {Array}
         * @private
         */
        _this._ml = [];
        /**
         * 鼠标事件中用到的Point对象池
         * @property _mp
         * @type {Array}
         * @private
         */
        _this._mp = [];
        /**
         * 每一个手指事件的对象池，为了click事件，得保证down和up是同一个手指标识
         * @property _mouseDownPoint
         * @type {Object}
         * @private
         */
        _this._mouseDownPoint = {};
        /**
         * 原始（html或其他）的鼠标事件名和引擎鼠标事件名的映射，TODO，字符串统统用MouseEvent的静态属性代替，事件名只维护一个地方
         * touchcancel:"onMouseUp"不常用，先不加
         * @property _mouseEventTypes
         * @type {{mousedown: string, mouseup: string, mousemove: string, touchstart: string, touchmove: string, touchend: string}}
         * @private
         */
        _this._mouseEventTypes = {
            //pc
            mousedown: "onMouseDown",
            mousemove: "onMouseMove",
            mouseup: "onMouseUp",
            //mobile
            touchstart: "onMouseDown",
            touchmove: "onMouseMove",
            touchend: "onMouseUp",
            //tbMini
            touchStart: "onMouseDown",
            touchMove: "onMouseMove",
            touchEnd: "onMouseUp"
        };
        _this.canvas = canvas;
        var s = _this;
        _this._instanceType = "Stage";
        Stage._stageList["canvas"] = s;
        s.stage = _this;
        s.name = "stageInstance_" + s.instanceId;
        s.desWidth = desWidth;
        s.desHeight = desHeight;
        s.divWidth = divWidth;
        s.divHeight = divHeight;
        if (!resolution) { //为了兼容以前的活动，以后删了
            //以前的活动外部设置了canvas的实际尺寸和显示尺寸
            console.warn("try to send param resolution, canvas‘s width and height will be setted up based on resolution");
            //这里设置_dpi
            s._dpi = canvas.width / divWidth;
        }
        else {
            //canvas实际尺寸处理
            s._dpi = resolution;
            var cWidth = divWidth * resolution, cHeight = divHeight * resolution;
            if (getEnv() == "tb") { //淘宝小程序环境有个白边，所以加点像素
                cWidth += resolution;
                cHeight += resolution;
            }
            canvas.width = cWidth;
            canvas.height = cHeight;
        }
        // console.log("%c ", "background: url(http://5b0988e595225.cdn.sohucs.com/images/20180315/d41842ad9b5443d3854a480ea49f3b09.gif) no-repeat center;padding-left:80px;padding-bottom: 80px;border-radius:50%;")
        //打印个版本号
        console.log("%cfyge version:" + VERSION, "text-shadow: 0 1px 0 #ccc,0 2px 0 #c9c9c9,0 3px 0 #bbb,0 4px 0 #b9b9b9,0 5px 0 #aaa,0 6px 1px rgba(0,0,0,.1),0 0 5px rgba(0,0,0,.1),0 1px 3px rgba(0,0,0,.3),0 3px 5px rgba(0,0,0,.2),0 5px 10px rgba(0,0,0,.25),0 10px 10px rgba(0,0,0,.2),0 20px 20px rgba(0,0,0,.15);font-size:3em");
        //webgl不支持时的兼容，回退canvas
        if (renderType == RENDERER_TYPE.WEBGL && !isWebGLSupported()) {
            renderType = RENDERER_TYPE.CANVAS;
            console.warn("your device doesn‘t support webgl,will use canvas2d instead");
        }
        if (renderType == RENDERER_TYPE.CANVAS) {
            var context = canvas.getContext("2d");
            s.renderObj = new CanvasRenderer(context, canvas.width, canvas.height);
        }
        else {
            var contextOptions = __assign({ alpha: true, antialias: false, premultipliedAlpha: true, stencil: true }, webglOptions);
            var context = canvas.getContext("webgl", contextOptions) || canvas.getContext("experimental-webgl", contextOptions);
            s.renderObj = new WebglRenderer(context, canvas.width, canvas.height);
            //监听下上下文丢失的情况
            if (getEnv() == "web") {
                canvas.addEventListener('webglcontextlost', s.renderObj.handleContextLost, false);
                canvas.addEventListener('webglcontextrestored', s.renderObj.handleContextRestored, false);
            }
        }
        //TODO,还有一种方式,传入分辨率和显示宽高,canvas尺寸在里面修改,这样要多传个参数,暂时不改传参,不然版本问题,
        //到时修改这个放到上面,因为渲染器也用到了canvas的尺寸,
        //注意淘宝小程序环境必须先设置canvas的尺寸再getContext,类似CanvasRenderTarget构造函数里的问题
        //分辨率,
        // s._dpi = canvas.width / divWidth;//这里不需要了
        s._stageCenter = stageCenter;
        s._scaleMode = fixedHeight ? "fixedHeight" : "fixedWidth";
        //设置缩放及视窗
        s._setAlign();
        //延时派发舞台初始化事件
        setTimeout(function () {
            //派发事件
            s.dispatchEvent(Event.INIT_STAGE);
        }, 100);
        return _this;
        //淘宝环境额外处理canvas偏移,到时需要修改id传入，再说把，不需要了，淘宝上返回的就是canvas上的显示坐标
        // if (getEnv() == "tb") {//暂时先去掉吧，会出现一些问题，有需要，手动设置canvasOffsetTb的xy，屏幕坐标
        //     s.offsetTimeId = setInterval(() => {
        //         //@ts-ignore
        //         my.createSelectorQuery().select('#canvas').boundingClientRect().exec((r) => {
        //             if (r && r[0]) {
        //                 s.canvasOffsetTb.x = r[0].left || 0;
        //                 s.canvasOffsetTb.y = r[0].top || 0;
        //             }
        //         });
        //     }, 200)
        // }
    }
    /**
     * 直接获取stage的引用，避免总是从Event.ADD_TO_STAGE 事件中去获取stage引用
     * @property getStage
     * @param {string} stageName
     * @return {any}
     * @since 2.0.0
     */
    Stage.getStage = function (stageName) {
        if (stageName === void 0) { stageName = "cusEngine"; }
        return Stage._stageList[stageName];
    };
    Object.defineProperty(Stage.prototype, "bgColor", {
        /**
         * 舞台的背景色，暂时无效，渲染器默认透明背景，且webgl模式下clearColor不会跟着修改，TODO 以后修改
         * @property bgColor
         * @public
         * @since 1.0.0
         * @type {number}
         * @default 0;
         */
        get: function () {
            return this._bgColor;
        },
        set: function (value) {
            if (this._bgColor === value)
                return;
            this._bgColor = value;
            this.renderObj.backgroundColor = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Stage.prototype, "stageWidth", {
        // private offsetTimeId: any
        get: function () {
            return this.viewRect.width;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Stage.prototype, "stageHeight", {
        get: function () {
            return this.viewRect.height;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Stage.prototype, "autoSteering", {
        /**
         * 是否自动转向，一般对于需要手机横屏自动更新内容朝向的设置为true，自动对齐设计尺寸和屏幕显示尺寸
         * 默认false
         * @property autoSteering
         * @public
         * @type {boolean}
         * @default false
         */
        get: function () {
            return this._autoSteering;
        },
        set: function (value) {
            if (this._autoSteering == value)
                return;
            this._autoSteering = value;
            //没啥性能问题，设置了就执行一次
            this._setAlign();
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Stage.prototype, "scaleMode", {
        /**
         * 缩放模式，暂时只有 "fixedWidth" | "fixedHeight"，
         * 以后有需要再加，同时修改构造函数传参fixedHeight
         */
        get: function () {
            return this._scaleMode;
        },
        set: function (value) {
            if (this._scaleMode == value)
                return;
            this._scaleMode = value;
            //没啥性能问题，设置了就执行一次
            this._setAlign();
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 处理适配，暂时不存在外部调用的情况
     */
    Stage.prototype._setAlign = function () {
        var s = this;
        var canvas = s.canvas;
        //实际尺寸和设计内容尺寸
        var divW = canvas.width, divH = canvas.height, desW = s.desWidth, desH = s.desHeight;
        //舞台设置居中处理锚点和位置偏移
        if (s._stageCenter) {
            s.anchorX = desW >> 1;
            s.anchorY = desH >> 1;
            s.x = (divW - desW) >> 1;
            s.y = (divH - desH) >> 1;
        }
        //设备是否为竖屏
        var isDivH = divH >= divW;
        //内容是否为竖屏内容
        var isDesH = desH >= desW;
        //处理下,显示尺寸宽高颠倒下
        if (s._autoSteering && isDesH != isDivH) {
            var d = divH;
            divH = divW;
            divW = d;
        }
        //默认定宽
        var scale = s._scaleMode == "fixedHeight" ? divH / desH : divW / desW;
        s.scaleX = scale;
        s.scaleY = scale;
        //未设置自动转向，或不需要转向
        if (!s._autoSteering || isDesH == isDivH) {
            s.rotation = 0;
            //没设置过居中的位移置0
            if (!s._stageCenter)
                s.x = s.y = 0;
        }
        else {
            //TODO,待考虑按什么决定角度正负
            if (desH > desW) {
                s.rotation = -90;
                //没设置过居中的
                if (!s._stageCenter)
                    s.y = divW;
            }
            else {
                s.rotation = 90;
                //没设置过居中的
                if (!s._stageCenter)
                    s.x = divH;
            }
        }
        //视窗计算
        s.viewRect = s.viewRect || new Rectangle();
        s.viewRect.x = (desW - divW / scale) >> 1;
        s.viewRect.y = (desH - divH / scale) >> 1;
        s.viewRect.width = desW - s.viewRect.x * 2;
        s.viewRect.height = desH - s.viewRect.y * 2;
        //额外逻辑,不设置舞台居中时,x,y为左上角,置0
        if (!s._stageCenter)
            s.viewRect.x = s.viewRect.y = 0;
    };
    /**
     * 移动端不常用
     * 微信浏览器使用情景:ios返回页面下面出现操作栏
     * 这里会按照原_dpi修改canvas的实际尺寸
     * 一般设备的dpi不会改变,
     * web全屏环境可不传参数,否则自行计算显示尺寸传入
     * @param divWidth
     * @param divHeight
     * @example
     *   window.addEventListener('resize', () => {stage.resize()});
     */
    Stage.prototype.resize = function (divWidth, divHeight) {
        if (getEnv() == "web") { //web环境不传当作全屏处理
            divWidth = divWidth || document.body.clientWidth;
            divHeight = divHeight || document.body.clientHeight;
        }
        if (!divWidth || !divWidth) {
            console.error("parm divWidth or divHeight cannot be empty");
            return;
        }
        var s = this, d = s._dpi, c = s.canvas;
        //如果一致不修改
        if (divWidth == s.divWidth && divHeight == s.divHeight)
            return;
        //这里修改canvas尺寸
        if (divWidth != s.divWidth)
            c.width = divWidth * d;
        if (divHeight != s.divHeight)
            c.height = divHeight * d;
        //赋值显示宽高
        s.divWidth = divWidth;
        s.divHeight = divHeight;
        //修改缩放显示及视窗
        s._setAlign();
        //渲染器修改尺寸
        s.renderObj.resize(c.width, c.height);
        //派发事件
        s.dispatchEvent(Event.RESIZE);
    };
    /**
     * 初始化鼠标事件
     * @method _initMouseEvent
     * @private
     */
    Stage.prototype._initMouseEvent = function (event, cp, sp, identifier) {
        event["_pd"] = false;
        event.clientX = cp.x;
        event.clientY = cp.y;
        event.stageX = sp.x;
        event.stageY = sp.y;
        event.identifier = identifier;
    };
    /**
     * 渲染器刷新stage
     * @method flush
     * @private
     * @return {void}
     */
    Stage.prototype.flush = function () {
        this.renderObj.render(this);
    };
    /**
     * 鼠标事件方法
     * @method onMouseEvent
     * @param e
     * @private
     */
    Stage.prototype.onMouseEvent = function (e) {
        //如果是web环境，且设置了阻止默认事件
        if (getEnv() == "web") {
            if (this.webMouseEventPreventDefault)
                e.preventDefault();
            if (this.webMouseEventStopPropagation)
                e.stopPropagation();
        }
        var s = this;
        //检查mouse或touch事件是否有，如果有的话，就触发事件函数
        if (EventDispatcher._totalMEC > 0) {
            var points = void 0;
            //事件类型
            var item = s._mouseEventTypes[e.type];
            var events = void 0;
            var event = void 0;
            //stageMousePoint
            var sp = void 0;
            //localPoint;
            var lp = void 0;
            //clientPoint
            var cp = void 0;
            //事件个数
            var eLen = void 0;
            var identifier = void 0;
            if (getOsType() == "pc") {
                e.identifier = 0;
                points = [e];
            }
            else {
                // points = [e.changedTouches[0]];
                points = e.changedTouches;
            }
            // points = [e.changedTouches[0]];
            //  points = [e.touches[0]];//不能用这个
            var _a = s.canvasOffsetTb, offsetX = _a.x, offsetY = _a.y;
            //
            if (getEnv() == "web") {
                var doc = document.documentElement;
                var box = s.canvas.getBoundingClientRect();
                offsetX = box.left + window.pageXOffset - doc.clientLeft;
                offsetY = box.top + window.pageYOffset - doc.clientTop;
            }
            for (var o = 0; o < points.length; o++) {
                if (!points[o])
                    continue;
                eLen = 0;
                events = [];
                identifier = "m" + points[o].identifier;
                if (s._mp.length > 0) {
                    cp = s._mp.shift();
                }
                else {
                    cp = new Point();
                }
                cp.x = ((points[o].pageX || points[o].x || points[o].b) - offsetX) * s._dpi; // devicePixelRatio;
                cp.y = ((points[o].pageY || points[o].y || points[o].c) - offsetY) * s._dpi; // devicePixelRatio;
                // my.alert({
                //   title: JSON.stringify(points[o])
                // });
                //计算舞台中的点
                sp = s.globalToLocal(cp, DisplayObject._bp);
                //检查是否有鼠标事件
                if (EventDispatcher.getMouseEventCount() > 0) {
                    if (!s._ml[eLen]) {
                        event = new MouseEvent(item);
                        s._ml[eLen] = event;
                    }
                    else {
                        event = s._ml[eLen];
                        event.type = item;
                    }
                    events[events.length] = event;
                    s._initMouseEvent(event, cp, sp, identifier);
                    eLen++;
                }
                if (item == "onMouseDown") {
                    s._mouseDownPoint[identifier] = cp;
                    //清空上次存在的显示列表
                }
                else if (item == "onMouseUp") {
                    if (s._mouseDownPoint[identifier]) {
                        if (Point.distance(s._mouseDownPoint[identifier], cp) < 20) {
                            //检查是否有添加对应的click事件
                            if (EventDispatcher.getMouseEventCount("onMouseClick") > 0) {
                                if (!s._ml[eLen]) {
                                    event = new MouseEvent("onMouseClick");
                                    s._ml[eLen] = event;
                                }
                                else {
                                    event = s._ml[eLen];
                                    event.type = "onMouseClick";
                                }
                                events[events.length] = event;
                                s._initMouseEvent(event, cp, sp, identifier);
                                eLen++;
                            }
                        }
                    }
                }
                if (eLen > 0) {
                    //有事件开始遍历显示列表
                    //找出最底层的显示对象
                    var d = s.hitTestPoint(cp, true);
                    // console.log(d)
                    var displayList = [];
                    // my.alert({
                    //   title: '55729:' + d.instanceId
                    // });
                    if (d) {
                        //证明有点击到事件,然后从最底层追上来,看看一路是否有人添加过mouse或touch事件,还要考虑mousechildren和阻止事件方法
                        //找出真正的target,因为有些父级可能会mouseChildren=false;
                        while (d) {
                            if (d["mouseChildren"] === false) {
                                //丢掉之前的层级,因为根本没用了
                                displayList.length = 0;
                            }
                            displayList[displayList.length] = d;
                            d = d.parent;
                        }
                    }
                    else {
                        displayList[displayList.length] = s;
                    }
                    var len = displayList.length;
                    for (var i = len - 1; i >= 0; i--) {
                        d = displayList[i];
                        for (var j = 0; j < eLen; j++) {
                            if (!events[j]["_pd"]) {
                                //有事件，且mouseEnable为true
                                if (d.hasEventListener(events[j].type) && d.mouseEnable) {
                                    events[j].target = d;
                                    events[j].currentTarget = displayList[0];
                                    lp = d.globalToLocal(cp, DisplayObject._bp);
                                    events[j].localX = lp.x;
                                    events[j].localY = lp.y;
                                    d.dispatchEvent(events[j]);
                                }
                            }
                        }
                    }
                    //这里一定要反转一下，因为会影响mouseOut mouseOver
                    displayList.reverse();
                    for (var i = len - 1; i >= 0; i--) {
                        d = displayList[i];
                        for (var j = 0; j < eLen; j++) {
                            if (!events[j]["_pd"]) {
                                //有事件，且mouseEnable为true
                                if (d.hasEventListener(events[j].type, false) && d.mouseEnable) {
                                    events[j].target = d;
                                    events[j].currentTarget = displayList[eLen - 1];
                                    lp = d.globalToLocal(cp, DisplayObject._bp);
                                    events[j].localX = lp.x;
                                    events[j].localY = lp.y;
                                    d.dispatchEvent(events[j], null, false);
                                }
                            }
                        }
                    }
                    //最后要和上一次的遍历者对比下，如果不相同则要触发onMouseOver和onMouseOut
                    if (item != "onMouseDown") {
                        if (EventDispatcher.getMouseEventCount("onMouseOver") > 0 || EventDispatcher.getMouseEventCount("onMouseOut") > 0) {
                            if (s._lastDpList[identifier]) {
                                //从第二个开始，因为第一个对象始终是stage顶级对象
                                var len1 = s._lastDpList[identifier].length;
                                var len2 = displayList.length;
                                len = len1 > len2 ? len1 : len2;
                                var isDiff = false;
                                var overEvent = void 0;
                                var outEvent = void 0;
                                for (var i = 1; i < len; i++) {
                                    if (!isDiff) {
                                        if (s._lastDpList[identifier][i] != displayList[i]) {
                                            //确定哪些有onMouseOver,哪些有onMouseOut
                                            isDiff = true;
                                            if (!s._ml[eLen]) {
                                                overEvent = new MouseEvent("onMouseOver");
                                                s._ml[eLen] = overEvent;
                                            }
                                            else {
                                                overEvent = s._ml[eLen];
                                                overEvent.type = "onMouseOver";
                                            }
                                            s._initMouseEvent(overEvent, cp, sp, identifier);
                                            eLen++;
                                            if (!s._ml[eLen]) {
                                                outEvent = new MouseEvent("onMouseOut");
                                                s._ml[eLen] = outEvent;
                                            }
                                            else {
                                                outEvent = s._ml[eLen];
                                                outEvent.type = "onMouseOut";
                                            }
                                            s._initMouseEvent(outEvent, cp, sp, identifier);
                                        }
                                    }
                                    if (isDiff) {
                                        if (s._lastDpList[identifier][i]) {
                                            //触发onMouseOut事件
                                            if (!outEvent["_pd"]) {
                                                d = s._lastDpList[identifier][i];
                                                if (d.hasEventListener("onMouseOut")) {
                                                    outEvent.currentTarget = s._lastDpList[identifier][len1 - 1];
                                                    outEvent.target = d;
                                                    lp = d.globalToLocal(cp, DisplayObject._bp);
                                                    outEvent.localX = lp.x;
                                                    outEvent.localY = lp.y;
                                                    d.dispatchEvent(outEvent);
                                                }
                                            }
                                        }
                                        if (displayList[i]) {
                                            //触发onMouseOver事件
                                            if (!overEvent["_pd"]) {
                                                d = displayList[i];
                                                if (d.hasEventListener("onMouseOver")) {
                                                    overEvent.currentTarget = displayList[len2 - 1];
                                                    overEvent.target = d;
                                                    lp = d.globalToLocal(cp, DisplayObject._bp);
                                                    overEvent.localX = lp.x;
                                                    overEvent.localY = lp.y;
                                                    d.dispatchEvent(overEvent);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        s._mp[s._mp.length] = cp;
                    }
                    if (item == "onMouseUp") {
                        delete s._mouseDownPoint[identifier];
                        delete s._lastDpList[identifier];
                    }
                    else {
                        s._lastDpList[identifier] = displayList;
                    }
                }
            }
        }
    };
    /**
     * 给舞台绑定canvas标签的鼠标代理事件（web环境下需要显示对象的鼠标事件时调用）
     * 自行调用，内部不主动调用，因为比如淘宝小程序环境方式不一致，需要用onMouseEvent
     */
    Stage.prototype.addWebMouseEvent = function () {
        var canvas = this.canvas;
        //有就可以执行
        if (!canvas || !canvas.addEventListener)
            return;
        var mouseEvent = this.onMouseEvent.bind(this);
        if (getOsType() == "pc") {
            canvas.addEventListener("mousedown", mouseEvent, false);
            canvas.addEventListener('mousemove', mouseEvent, false);
            canvas.addEventListener('mouseup', mouseEvent, false);
        }
        else {
            canvas.addEventListener("touchstart", mouseEvent, false);
            canvas.addEventListener('touchmove', mouseEvent, false);
            canvas.addEventListener('touchend', mouseEvent, false);
        }
    };
    // /**
    //  * 直接修改了，用视窗，
    //  * 一般用于滤镜等等，对于舞台，超出viewPort的肯定不显示，没必要测量（后续考虑也测量，万一测量出的更小呢）
    //  */
    // public getBounds(): Rectangle {20211202注释，因为滤镜上会有问题，stage是带矩阵的，viewRect没经过换算
    //     return this.viewRect;
    // }
    Stage.prototype.destroy = function () {
        var s = this;
        // if (getEnv() == "tb") clearInterval(s.offsetTimeId);
        //web环境下，渲染方式webgl模式时，移除webgl上下文丢失事件
        if (getEnv() == "web" && s.renderObj.type == RENDERER_TYPE.WEBGL) {
            s.canvas.removeEventListener('webglcontextlost', s.renderObj.handleContextLost, false);
            s.canvas.removeEventListener('webglcontextrestored', s.renderObj.handleContextRestored, false);
        }
        //然后销毁渲染器
        s.renderObj.destroy();
        s.renderObj = null;
        s.viewRect = null;
        s._lastDpList = null;
        s._ml = null;
        _super.prototype.destroy.call(this);
    };
    /**
     * @property _stageList
     * @static
     * @type {Object}
     * @private
     */
    Stage._stageList = {};
    return Stage;
}(Container));

/**
 * A GraphicsData object.
 * 记录图形数据
 */
var GraphicsData = /** @class */ (function (_super) {
    __extends(GraphicsData, _super);
    /**
     *
     */
    function GraphicsData(shape, fillStyle, lineStyle, matrix) {
        if (fillStyle === void 0) { fillStyle = null; }
        if (lineStyle === void 0) { lineStyle = null; }
        if (matrix === void 0) { matrix = null; }
        var _this = _super.call(this) || this;
        _this._instanceType = "GraphicsData";
        _this.shape = shape;
        _this.lineStyle = lineStyle;
        _this.fillStyle = fillStyle;
        _this.matrix = matrix;
        _this.holes = [];
        _this.type = shape.type;
        _this.points = [];
        return _this;
    }
    /**
     * Creates a new GraphicsData object with the same values as this one.
     *
     * @return {GraphicsData} Cloned GraphicsData object
     */
    GraphicsData.prototype.clone = function () {
        return new GraphicsData(this.shape, this.fillStyle, this.lineStyle, this.matrix);
    };
    /**
     * Destroys the Graphics data.
     */
    GraphicsData.prototype.destroy = function () {
        this.shape = null;
        this.holes.length = 0;
        this.holes = null;
        this.points.length = 0;
        this.points = null;
        this.lineStyle = null;
        this.fillStyle = null;
    };
    return GraphicsData;
}(HashObject));

/**
 * 将显示对象画在上面的贴图，这是基础纹理，一般用RenderTexture
 * 注意绘制前纹理加载完成
 * For example:
 *
 * ```js
 * let renderer = CanvasRenderer(context,1024, 1024);
 * let baseRenderTexture = new BaseRenderTexture(800, 600);
 * let renderTexture = new RenderTexture(baseRenderTexture);
 * let sprite = Sprite.fromImage("spinObj_01.png");
 *
 * sprite.position.x = 800/2;
 * sprite.position.y = 600/2;
 * sprite.anchorTexture.x = 0.5;
 * sprite.anchorTexture.y = 0.5;
 *
 * renderer.render(sprite,renderTexture);
 * ```
 *
 *
 * @class
 * @extends BaseTexture
 */
var BaseRenderTexture = /** @class */ (function (_super) {
    __extends(BaseRenderTexture, _super);
    /**
     * @param {number} [width=100] - 宽度
     * @param {number} [height=100] - 高度
     * @param {number} [scaleMode=SCALE_MODES.LINEAR] -  {@link SCALE_MODES}
     */
    function BaseRenderTexture(width, height, scaleMode) {
        if (width === void 0) { width = 100; }
        if (height === void 0) { height = 100; }
        if (scaleMode === void 0) { scaleMode = SCALE_MODES.LINEAR; }
        var _this = _super.call(this, null, scaleMode) || this;
        _this.width = Math.ceil(width);
        _this.height = Math.ceil(height);
        _this.scaleMode = scaleMode;
        _this.hasLoaded = true;
        _this._glRenderTargets = {};
        _this._canvasRenderTarget = null;
        _this.valid = false;
        return _this;
    }
    /**
     * 重置尺寸
     * @param {number} width - 宽度
     * @param {number} height - 高度
     */
    BaseRenderTexture.prototype.resize = function (width, height) {
        width = Math.ceil(width);
        height = Math.ceil(height);
        if (width === this.width && height === this.height) {
            return;
        }
        this.valid = (width > 0 && height > 0);
        this.width = width;
        this.height = height;
        if (!this.valid) {
            return;
        }
        this.dispatchEvent('update');
    };
    /**
     * 销毁
     */
    BaseRenderTexture.prototype.destroy = function () {
        _super.prototype.destroy.call(this);
    };
    return BaseRenderTexture;
}(BaseTexture));

/**
 * 将显示对象画在上面的贴图，就是快照
 * 注意绘制前纹理加载完成
 * For example:
 *
 * ```js
 * let renderer = CanvasRenderer(1024, 1024);
 * let renderTexture = RenderTexture.create(800, 600);
 * let sprite = Sprite.fromImage("aaa.png");
 *
 * sprite.x = 800/2;
 * sprite.y = 600/2;
 * sprite.anchorTexture.set(0.5,0.5);
 * //sprite.setTransform();会重置属性
 *
 * renderer.render(sprite, renderTexture);
 * ```
 *
 * @class
 * @extends Texture
 */
var RenderTexture = /** @class */ (function (_super) {
    __extends(RenderTexture, _super);
    /**
     * @param {BaseRenderTexture} baseRenderTexture
     * @param {Rectangle} [frame]
     */
    function RenderTexture(baseRenderTexture, frame) {
        var _this = _super.call(this, baseRenderTexture, frame) || this;
        _this.valid = true;
        _this.updateUvs();
        return _this;
    }
    /**
     * 重置尺寸
     * @param {number} width - 宽度
     * @param {number} height - 高度
     * @param {boolean} doNotResizeBaseTexture - 是否不重置基础纹理的尺寸，默认false，表示也重置
     */
    RenderTexture.prototype.resize = function (width, height, doNotResizeBaseTexture) {
        if (doNotResizeBaseTexture === void 0) { doNotResizeBaseTexture = false; }
        width = Math.ceil(width);
        height = Math.ceil(height);
        // TODO - could be not required..
        this.valid = (width > 0 && height > 0);
        this._frame.width = this.orig.width = width;
        this._frame.height = this.orig.height = height;
        if (!doNotResizeBaseTexture) {
            this.baseTexture["resize"](width, height);
        }
        this.updateUvs();
    };
    /**
     * 创建renderTexture快捷静态方法
     * @param {number} [width=100] - 宽度
     * @param {number} [height=100] - 高度
     * @param {number} [scaleMode=settings.SCALE_MODE] - {@link SCALE_MODES}
     * @return {RenderTexture}
     */
    RenderTexture.create = function (width, height, scaleMode) {
        if (scaleMode === void 0) { scaleMode = SCALE_MODES.LINEAR; }
        return new RenderTexture(new BaseRenderTexture(width, height, scaleMode));
    };
    return RenderTexture;
}(Texture));

/**
 * 圆形
 */
var Circle = /** @class */ (function () {
    /**
     * @param {number} [x=0] - The X coordinate of the center of this circle
     * @param {number} [y=0] - The Y coordinate of the center of this circle
     * @param {number} [radius=0] - The radius of the circle
     */
    function Circle(x, y, radius) {
        if (x === void 0) { x = 0; }
        if (y === void 0) { y = 0; }
        if (radius === void 0) { radius = 0; }
        this.x = x;
        this.y = y;
        this.radius = radius;
        this.type = SHAPES.CIRC;
    }
    /**
     * Creates a clone of this Circle instance
     *
     * @return {Circle} a copy of the Circle
     */
    Circle.prototype.clone = function () {
        return new Circle(this.x, this.y, this.radius);
    };
    /**
     * @param {Point} point - The point to test
     * @return {boolean} Whether the x/y coordinates are within this Circle
     */
    Circle.prototype.isPointIn = function (point) {
        if (this.radius <= 0) {
            return false;
        }
        var r2 = this.radius * this.radius;
        var dx = (this.x - point.x);
        var dy = (this.y - point.y);
        dx *= dx;
        dy *= dy;
        return (dx + dy <= r2);
    };
    /**
    * Returns the framing rectangle of the circle as a Rectangle object
    *
    * @return {Rectangle} the framing rectangle
    */
    Circle.prototype.getBounds = function () {
        return new Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2);
    };
    return Circle;
}());

/**
 * The Ellipse object can be used to specify a hit area for displayObjects
 *
 */
var Ellipse = /** @class */ (function () {
    /**
     * @param {number} [x=0] - The X coordinate of the center of this circle
     * @param {number} [y=0] - The Y coordinate of the center of this circle
     * @param {number} [width=0] - The half width of this ellipse
     * @param {number} [height=0] - The half height of this ellipse
     */
    function Ellipse(x, y, width, height) {
        if (x === void 0) { x = 0; }
        if (y === void 0) { y = 0; }
        if (width === void 0) { width = 0; }
        if (height === void 0) { height = 0; }
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.type = SHAPES.ELIP;
    }
    /**
     * Creates a clone of this Ellipse instance
     *
     * @return {Ellipse} a copy of the ellipse
     */
    Ellipse.prototype.clone = function () {
        return new Ellipse(this.x, this.y, this.width, this.height);
    };
    /**
     * Checks whether the x and y coordinates given are contained within this ellipse
     *
     * @param {Point} point - The  point to test
     * @return {boolean} Whether the x/y coords are within this ellipse
     */
    Ellipse.prototype.isPointIn = function (point) {
        if (this.width <= 0 || this.height <= 0) {
            return false;
        }
        // normalize the coords to an ellipse with center 0,0
        var normx = ((point.x - this.x) / this.width);
        var normy = ((point.y - this.y) / this.height);
        normx *= normx;
        normy *= normy;
        return (normx + normy <= 1);
    };
    /**
     * Returns the framing rectangle of the ellipse as a Rectangle object
     *
     * @return {Rectangle} the framing rectangle
     */
    Ellipse.prototype.getBounds = function () {
        return new Rectangle(this.x - this.width, this.y - this.height, this.width, this.height);
    };
    return Ellipse;
}());

/**
 *
 */
var Polygon = /** @class */ (function () {
    /**
     * new Polygon(new Point(), new Point(), ...)
     *
     * new Polygon([x,y, x,y, ...])
     * new Polygon(x,y, x,y, x,y, ...)
     * @param {Point[]|number[]} points - This can be an array of Points
     *  that form the polygon, a flat array of numbers that will be interpreted as [x,y, x,y, ...], or
     *  the arguments passed can be all the points of the polygon e.g.
     *  `new Polygon(new Point(), new Point(), ...)`, or the arguments passed can be flat
     *  x,y values e.g. `new Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are Numbers.
     */
    function Polygon() {
        var points = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            points[_i] = arguments[_i];
        }
        if (Array.isArray(points[0])) {
            points = points[0];
        }
        // if this is an array of points, convert it to a flat array of numbers
        if (points[0] instanceof Point) {
            var p = [];
            for (var i = 0, il = points.length; i < il; i++) {
                p.push(points[i].x, points[i].y);
            }
            points = p;
        }
        this.closed = true;
        this.points = points;
        this.type = SHAPES.POLY;
    }
    /**
     * Creates a clone of this polygon
     *
     * @return {Polygon} a copy of the polygon
     */
    Polygon.prototype.clone = function () {
        return new Polygon(this.points.slice());
    };
    // /**
    //  * Closes the polygon, adding points if necessary.
    //  *
    //  */
    // close() {
    //     const points = this.points;
    //     // close the poly if the value is true!
    //     if (points[0] !== points[points.length - 2] || points[1] !== points[points.length - 1]) {
    //         points.push(points[0], points[1]);
    //     }
    // }
    /**
     * Checks whether the x and y coordinates passed to this function are contained within this polygon
     *
     * @param {Point} point - The  point to test
     * @return {boolean} Whether the x/y coordinates are within this polygon
     */
    Polygon.prototype.isPointIn = function (point) {
        var x = point.x;
        var y = point.y;
        var inside = false;
        // use some raycasting to test hits
        // https://github.com/substack/point-in-polygon/blob/master/index.js
        var length = this.points.length / 2;
        for (var i = 0, j = length - 1; i < length; j = i++) {
            var xi = this.points[i * 2];
            var yi = this.points[(i * 2) + 1];
            var xj = this.points[j * 2];
            var yj = this.points[(j * 2) + 1];
            var intersect = ((yi > y) !== (yj > y)) && (x < ((xj - xi) * ((y - yi) / (yj - yi))) + xi);
            if (intersect) {
                inside = !inside;
            }
        }
        return inside;
    };
    return Polygon;
}());

/**
 * The Rounded Rectangle object is an area that has nice rounded corners, as indicated by its
 * top-left corner point (x, y) and by its width and its height and its radius.
 */
var RoundedRectangle = /** @class */ (function () {
    /**
     * @param {number} [x=0] - The X coordinate of the upper-left corner of the rounded rectangle
     * @param {number} [y=0] - The Y coordinate of the upper-left corner of the rounded rectangle
     * @param {number} [width=0] - The overall width of this rounded rectangle
     * @param {number} [height=0] - The overall height of this rounded rectangle
     * @param {number} [radius=20] - Controls the radius of the rounded corners
     */
    function RoundedRectangle(x, y, width, height, radius) {
        if (x === void 0) { x = 0; }
        if (y === void 0) { y = 0; }
        if (width === void 0) { width = 0; }
        if (height === void 0) { height = 0; }
        if (radius === void 0) { radius = 20; }
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        //计算最大圆角
        var max = (width < height ? width : height) / 2;
        //小于0取反
        radius = radius < 0 ? -radius : radius;
        //大于max取max
        radius = radius > max ? max : radius;
        // //等于最大圆角时额外处理下，否则有点重合
        // if (radius == max) radius -= 0.0000000001
        this.radius = radius;
        this.type = SHAPES.RREC;
    }
    /**
     * Creates a clone of this Rounded Rectangle
     *
     * @return {RoundedRectangle} a copy of the rounded rectangle
     */
    RoundedRectangle.prototype.clone = function () {
        return new RoundedRectangle(this.x, this.y, this.width, this.height, this.radius);
    };
    /**
     * Checks whether the x and y coordinates given are contained within this ellipse
     *
     * @param {Point} point - The  point to test
     * @return {boolean} Whether the x/y coords are within this ellipse
     */
    RoundedRectangle.prototype.isPointIn = function (point) {
        var x = point.x;
        var y = point.y;
        if (this.width <= 0 || this.height <= 0) {
            return false;
        }
        if (x >= this.x && x <= this.x + this.width) {
            if (y >= this.y && y <= this.y + this.height) {
                if ((y >= this.y + this.radius && y <= this.y + this.height - this.radius)
                    || (x >= this.x + this.radius && x <= this.x + this.width - this.radius)) {
                    return true;
                }
                var dx = x - (this.x + this.radius);
                var dy = y - (this.y + this.radius);
                var radius2 = this.radius * this.radius;
                if ((dx * dx) + (dy * dy) <= radius2) {
                    return true;
                }
                dx = x - (this.x + this.width - this.radius);
                if ((dx * dx) + (dy * dy) <= radius2) {
                    return true;
                }
                dy = y - (this.y + this.height - this.radius);
                if ((dx * dx) + (dy * dy) <= radius2) {
                    return true;
                }
                dx = x - (this.x + this.radius);
                if ((dx * dx) + (dy * dy) <= radius2) {
                    return true;
                }
            }
        }
        return false;
    };
    return RoundedRectangle;
}());

function earcut(data, holeIndices, dim) {
    dim = dim || 2;
    var hasHoles = holeIndices && holeIndices.length, outerLen = hasHoles ? holeIndices[0] * dim : data.length, outerNode = linkedList(data, 0, outerLen, dim, true), triangles = [];
    if (!outerNode || outerNode.next === outerNode.prev)
        return triangles;
    var minX, minY, maxX, maxY, x, y, invSize;
    if (hasHoles)
        outerNode = eliminateHoles(data, holeIndices, outerNode, dim);
    // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
    if (data.length > 80 * dim) {
        minX = maxX = data[0];
        minY = maxY = data[1];
        for (var i = dim; i < outerLen; i += dim) {
            x = data[i];
            y = data[i + 1];
            if (x < minX)
                minX = x;
            if (y < minY)
                minY = y;
            if (x > maxX)
                maxX = x;
            if (y > maxY)
                maxY = y;
        }
        // minX, minY and invSize are later used to transform coords into integers for z-order calculation
        invSize = Math.max(maxX - minX, maxY - minY);
        invSize = invSize !== 0 ? 1 / invSize : 0;
    }
    earcutLinked(outerNode, triangles, dim, minX, minY, invSize);
    return triangles;
}
// create a circular doubly linked list from polygon points in the specified winding order
function linkedList(data, start, end, dim, clockwise) {
    var i, last;
    if (clockwise === (signedArea(data, start, end, dim) > 0)) {
        for (i = start; i < end; i += dim)
            last = insertNode(i, data[i], data[i + 1], last);
    }
    else {
        for (i = end - dim; i >= start; i -= dim)
            last = insertNode(i, data[i], data[i + 1], last);
    }
    if (last && equals(last, last.next)) {
        removeNode(last);
        last = last.next;
    }
    return last;
}
// eliminate colinear or duplicate points
function filterPoints(start, end) {
    if (!start)
        return start;
    if (!end)
        end = start;
    var p = start, again;
    do {
        again = false;
        if (!p.steiner && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) {
            removeNode(p);
            p = end = p.prev;
            if (p === p.next)
                break;
            again = true;
        }
        else {
            p = p.next;
        }
    } while (again || p !== end);
    return end;
}
// main ear slicing loop which triangulates a polygon (given as a linked list)
function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) {
    if (!ear)
        return;
    // interlink polygon nodes in z-order
    if (!pass && invSize)
        indexCurve(ear, minX, minY, invSize);
    var stop = ear, prev, next;
    // iterate through ears, slicing them one by one
    while (ear.prev !== ear.next) {
        prev = ear.prev;
        next = ear.next;
        if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) {
            // cut off the triangle
            triangles.push(prev.i / dim);
            triangles.push(ear.i / dim);
            triangles.push(next.i / dim);
            removeNode(ear);
            // skipping the next vertex leads to less sliver triangles
            ear = next.next;
            stop = next.next;
            continue;
        }
        ear = next;
        // if we looped through the whole remaining polygon and can't find any more ears
        if (ear === stop) {
            // try filtering points and slicing again
            if (!pass) {
                earcutLinked(filterPoints(ear), triangles, dim, minX, minY, invSize, 1);
                // if this didn't work, try curing all small self-intersections locally
            }
            else if (pass === 1) {
                ear = cureLocalIntersections(ear, triangles, dim);
                earcutLinked(ear, triangles, dim, minX, minY, invSize, 2);
                // as a last resort, try splitting the remaining polygon into two
            }
            else if (pass === 2) {
                splitEarcut(ear, triangles, dim, minX, minY, invSize);
            }
            break;
        }
    }
}
// check whether a polygon node forms a valid ear with adjacent nodes
function isEar(ear) {
    var a = ear.prev, b = ear, c = ear.next;
    if (area(a, b, c) >= 0)
        return false; // reflex, can't be an ear
    // now make sure we don't have other points inside the potential ear
    var p = ear.next.next;
    while (p !== ear.prev) {
        if (pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
            area(p.prev, p, p.next) >= 0)
            return false;
        p = p.next;
    }
    return true;
}
function isEarHashed(ear, minX, minY, invSize) {
    var a = ear.prev, b = ear, c = ear.next;
    if (area(a, b, c) >= 0)
        return false; // reflex, can't be an ear
    // triangle bbox; min & max are calculated like this for speed
    var minTX = a.x < b.x ? (a.x < c.x ? a.x : c.x) : (b.x < c.x ? b.x : c.x), minTY = a.y < b.y ? (a.y < c.y ? a.y : c.y) : (b.y < c.y ? b.y : c.y), maxTX = a.x > b.x ? (a.x > c.x ? a.x : c.x) : (b.x > c.x ? b.x : c.x), maxTY = a.y > b.y ? (a.y > c.y ? a.y : c.y) : (b.y > c.y ? b.y : c.y);
    // z-order range for the current triangle bbox;
    var minZ = zOrder(minTX, minTY, minX, minY, invSize), maxZ = zOrder(maxTX, maxTY, minX, minY, invSize);
    var p = ear.prevZ, n = ear.nextZ;
    // look for points inside the triangle in both directions
    while (p && p.z >= minZ && n && n.z <= maxZ) {
        if (p !== ear.prev && p !== ear.next &&
            pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
            area(p.prev, p, p.next) >= 0)
            return false;
        p = p.prevZ;
        if (n !== ear.prev && n !== ear.next &&
            pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) &&
            area(n.prev, n, n.next) >= 0)
            return false;
        n = n.nextZ;
    }
    // look for remaining points in decreasing z-order
    while (p && p.z >= minZ) {
        if (p !== ear.prev && p !== ear.next &&
            pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
            area(p.prev, p, p.next) >= 0)
            return false;
        p = p.prevZ;
    }
    // look for remaining points in increasing z-order
    while (n && n.z <= maxZ) {
        if (n !== ear.prev && n !== ear.next &&
            pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) &&
            area(n.prev, n, n.next) >= 0)
            return false;
        n = n.nextZ;
    }
    return true;
}
// go through all polygon nodes and cure small local self-intersections
function cureLocalIntersections(start, triangles, dim) {
    var p = start;
    do {
        var a = p.prev, b = p.next.next;
        if (!equals(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) {
            triangles.push(a.i / dim);
            triangles.push(p.i / dim);
            triangles.push(b.i / dim);
            // remove two nodes involved
            removeNode(p);
            removeNode(p.next);
            p = start = b;
        }
        p = p.next;
    } while (p !== start);
    return p;
}
// try splitting polygon into two and triangulate them independently
function splitEarcut(start, triangles, dim, minX, minY, invSize) {
    // look for a valid diagonal that divides the polygon into two
    var a = start;
    do {
        var b = a.next.next;
        while (b !== a.prev) {
            if (a.i !== b.i && isValidDiagonal(a, b)) {
                // split the polygon in two by the diagonal
                var c = splitPolygon(a, b);
                // filter colinear points around the cuts
                a = filterPoints(a, a.next);
                c = filterPoints(c, c.next);
                // run earcut on each half
                earcutLinked(a, triangles, dim, minX, minY, invSize);
                earcutLinked(c, triangles, dim, minX, minY, invSize);
                return;
            }
            b = b.next;
        }
        a = a.next;
    } while (a !== start);
}
// link every hole into the outer loop, producing a single-ring polygon without holes
function eliminateHoles(data, holeIndices, outerNode, dim) {
    var queue = [], i, len, start, end, list;
    for (i = 0, len = holeIndices.length; i < len; i++) {
        start = holeIndices[i] * dim;
        end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
        list = linkedList(data, start, end, dim, false);
        if (list === list.next)
            list.steiner = true;
        queue.push(getLeftmost(list));
    }
    queue.sort(compareX);
    // process holes from left to right
    for (i = 0; i < queue.length; i++) {
        eliminateHole(queue[i], outerNode);
        outerNode = filterPoints(outerNode, outerNode.next);
    }
    return outerNode;
}
function compareX(a, b) {
    return a.x - b.x;
}
// find a bridge between vertices that connects hole with an outer ring and and link it
function eliminateHole(hole, outerNode) {
    outerNode = findHoleBridge(hole, outerNode);
    if (outerNode) {
        var b = splitPolygon(outerNode, hole);
        filterPoints(b, b.next);
    }
}
// David Eberly's algorithm for finding a bridge between hole and outer polygon
function findHoleBridge(hole, outerNode) {
    var p = outerNode, hx = hole.x, hy = hole.y, qx = -Infinity, m;
    // find a segment intersected by a ray from the hole's leftmost point to the left;
    // segment's endpoint with lesser x will be potential connection point
    do {
        if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
            var x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
            if (x <= hx && x > qx) {
                qx = x;
                if (x === hx) {
                    if (hy === p.y)
                        return p;
                    if (hy === p.next.y)
                        return p.next;
                }
                m = p.x < p.next.x ? p : p.next;
            }
        }
        p = p.next;
    } while (p !== outerNode);
    if (!m)
        return null;
    if (hx === qx)
        return m.prev; // hole touches outer segment; pick lower endpoint
    // look for points inside the triangle of hole point, segment intersection and endpoint;
    // if there are no points found, we have a valid connection;
    // otherwise choose the point of the minimum angle with the ray as connection point
    var stop = m, mx = m.x, my = m.y, tanMin = Infinity, tan;
    p = m.next;
    while (p !== stop) {
        if (hx >= p.x && p.x >= mx && hx !== p.x &&
            pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {
            tan = Math.abs(hy - p.y) / (hx - p.x); // tangential
            if ((tan < tanMin || (tan === tanMin && p.x > m.x)) && locallyInside(p, hole)) {
                m = p;
                tanMin = tan;
            }
        }
        p = p.next;
    }
    return m;
}
// interlink polygon nodes in z-order
function indexCurve(start, minX, minY, invSize) {
    var p = start;
    do {
        if (p.z === null)
            p.z = zOrder(p.x, p.y, minX, minY, invSize);
        p.prevZ = p.prev;
        p.nextZ = p.next;
        p = p.next;
    } while (p !== start);
    p.prevZ.nextZ = null;
    p.prevZ = null;
    sortLinked(p);
}
// Simon Tatham's linked list merge sort algorithm
// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
function sortLinked(list) {
    var i, p, q, e, tail, numMerges, pSize, qSize, inSize = 1;
    do {
        p = list;
        list = null;
        tail = null;
        numMerges = 0;
        while (p) {
            numMerges++;
            q = p;
            pSize = 0;
            for (i = 0; i < inSize; i++) {
                pSize++;
                q = q.nextZ;
                if (!q)
                    break;
            }
            qSize = inSize;
            while (pSize > 0 || (qSize > 0 && q)) {
                if (pSize !== 0 && (qSize === 0 || !q || p.z <= q.z)) {
                    e = p;
                    p = p.nextZ;
                    pSize--;
                }
                else {
                    e = q;
                    q = q.nextZ;
                    qSize--;
                }
                if (tail)
                    tail.nextZ = e;
                else
                    list = e;
                e.prevZ = tail;
                tail = e;
            }
            p = q;
        }
        tail.nextZ = null;
        inSize *= 2;
    } while (numMerges > 1);
    return list;
}
// z-order of a point given coords and inverse of the longer side of data bbox
function zOrder(x, y, minX, minY, invSize) {
    // coords are transformed into non-negative 15-bit integer range
    x = 32767 * (x - minX) * invSize;
    y = 32767 * (y - minY) * invSize;
    x = (x | (x << 8)) & 0x00FF00FF;
    x = (x | (x << 4)) & 0x0F0F0F0F;
    x = (x | (x << 2)) & 0x33333333;
    x = (x | (x << 1)) & 0x55555555;
    y = (y | (y << 8)) & 0x00FF00FF;
    y = (y | (y << 4)) & 0x0F0F0F0F;
    y = (y | (y << 2)) & 0x33333333;
    y = (y | (y << 1)) & 0x55555555;
    return x | (y << 1);
}
// find the leftmost node of a polygon ring
function getLeftmost(start) {
    var p = start, leftmost = start;
    do {
        if (p.x < leftmost.x || (p.x === leftmost.x && p.y < leftmost.y))
            leftmost = p;
        p = p.next;
    } while (p !== start);
    return leftmost;
}
// check if a point lies within a convex triangle
function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
    return (cx - px) * (ay - py) - (ax - px) * (cy - py) >= 0 &&
        (ax - px) * (by - py) - (bx - px) * (ay - py) >= 0 &&
        (bx - px) * (cy - py) - (cx - px) * (by - py) >= 0;
}
// check if a diagonal between two polygon nodes is valid (lies in polygon interior)
function isValidDiagonal(a, b) {
    return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) &&
        locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b);
}
// signed area of a triangle
function area(p, q, r) {
    return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
}
// check if two points are equal
function equals(p1, p2) {
    return p1.x === p2.x && p1.y === p2.y;
}
// check if two segments intersect
function intersects(p1, q1, p2, q2) {
    if ((equals(p1, q1) && equals(p2, q2)) ||
        (equals(p1, q2) && equals(p2, q1)))
        return true;
    return area(p1, q1, p2) > 0 !== area(p1, q1, q2) > 0 &&
        area(p2, q2, p1) > 0 !== area(p2, q2, q1) > 0;
}
// check if a polygon diagonal intersects any polygon segments
function intersectsPolygon(a, b) {
    var p = a;
    do {
        if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&
            intersects(p, p.next, a, b))
            return true;
        p = p.next;
    } while (p !== a);
    return false;
}
// check if a polygon diagonal is locally inside the polygon
function locallyInside(a, b) {
    return area(a.prev, a, a.next) < 0 ?
        area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 :
        area(a, b, a.prev) < 0 || area(a, a.next, b) < 0;
}
// check if the middle point of a polygon diagonal is inside the polygon
function middleInside(a, b) {
    var p = a, inside = false, px = (a.x + b.x) / 2, py = (a.y + b.y) / 2;
    do {
        if (((p.y > py) !== (p.next.y > py)) && p.next.y !== p.y &&
            (px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x))
            inside = !inside;
        p = p.next;
    } while (p !== a);
    return inside;
}
// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
// if one belongs to the outer ring and another to a hole, it merges it into a single ring
function splitPolygon(a, b) {
    var a2 = new Node(a.i, a.x, a.y), b2 = new Node(b.i, b.x, b.y), an = a.next, bp = b.prev;
    a.next = b;
    b.prev = a;
    a2.next = an;
    an.prev = a2;
    b2.next = a2;
    a2.prev = b2;
    bp.next = b2;
    b2.prev = bp;
    return b2;
}
// create a node and optionally link it with previous one (in a circular doubly linked list)
function insertNode(i, x, y, last) {
    var p = new Node(i, x, y);
    if (!last) {
        p.prev = p;
        p.next = p;
    }
    else {
        p.next = last.next;
        p.prev = last;
        last.next.prev = p;
        last.next = p;
    }
    return p;
}
function removeNode(p) {
    p.next.prev = p.prev;
    p.prev.next = p.next;
    if (p.prevZ)
        p.prevZ.nextZ = p.nextZ;
    if (p.nextZ)
        p.nextZ.prevZ = p.prevZ;
}
function Node(i, x, y) {
    // vertex index in coordinates array
    this.i = i;
    // vertex coordinates
    this.x = x;
    this.y = y;
    // previous and next vertex nodes in a polygon ring
    this.prev = null;
    this.next = null;
    // z-order curve value
    this.z = null;
    // previous and next nodes in z-order
    this.prevZ = null;
    this.nextZ = null;
    // indicates whether this is a steiner point
    this.steiner = false;
}
// return a percentage difference between the polygon area and its triangulation area;
// used to verify correctness of triangulation
earcut["deviation"] = function (data, holeIndices, dim, triangles) {
    var hasHoles = holeIndices && holeIndices.length;
    var outerLen = hasHoles ? holeIndices[0] * dim : data.length;
    var polygonArea = Math.abs(signedArea(data, 0, outerLen, dim));
    if (hasHoles) {
        for (var i = 0, len = holeIndices.length; i < len; i++) {
            var start = holeIndices[i] * dim;
            var end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
            polygonArea -= Math.abs(signedArea(data, start, end, dim));
        }
    }
    var trianglesArea = 0;
    for (i = 0; i < triangles.length; i += 3) {
        var a = triangles[i] * dim;
        var b = triangles[i + 1] * dim;
        var c = triangles[i + 2] * dim;
        trianglesArea += Math.abs((data[a] - data[c]) * (data[b + 1] - data[a + 1]) -
            (data[a] - data[b]) * (data[c + 1] - data[a + 1]));
    }
    return polygonArea === 0 && trianglesArea === 0 ? 0 :
        Math.abs((trianglesArea - polygonArea) / polygonArea);
};
function signedArea(data, start, end, dim) {
    var sum = 0;
    for (var i = start, j = end - dim; i < end; i += dim) {
        sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
        j = i;
    }
    return sum;
}
// turn a polygon in a multi-dimensional array form (e.g. as in GeoJSON) into a form Earcut accepts
earcut["flatten"] = function (data) {
    var dim = data[0][0].length, result = { vertices: [], holes: [], dimensions: dim }, holeIndex = 0;
    for (var i = 0; i < data.length; i++) {
        for (var j = 0; j < data[i].length; j++) {
            for (var d = 0; d < dim; d++)
                result.vertices.push(data[i][j][d]);
        }
        if (i > 0) {
            holeIndex += data[i - 1].length;
            result.holes.push(holeIndex);
        }
    }
    return result;
};

/**
 * Builds a polygon to draw
 *
 * Ignored from docs since it is not directly exposed.
 *
 * @ignore
 * @private
 * @param {WebGLGraphicsData} graphicsData - The graphics object containing all the necessary properties
 * @param {object} webGLData - an object containing all the WebGL-specific information to create this shape
 * @param {object} webGLDataNativeLines - an object containing all the WebGL-specific information to create nativeLines
 */
var buildPoly = {
    build: function (graphicsData) {
        graphicsData.points = graphicsData.shape.points.slice();
    },
    triangulate: function (graphicsData, graphicsGeometry) {
        var points = graphicsData.points;
        var holes = graphicsData.holes;
        var verts = graphicsGeometry.verts;
        var indices = graphicsGeometry.indices;
        if (points.length >= 6) {
            var holeArray = [];
            // Process holes..
            for (var i = 0; i < holes.length; i++) {
                var hole = holes[i];
                holeArray.push(points.length / 2);
                points = points.concat(hole.points);
            }
            // sort color
            var triangles = earcut(points, holeArray, 2);
            if (!triangles) {
                return;
            }
            var vertPos = verts.length / 2;
            for (var i = 0; i < triangles.length; i += 3) {
                indices.push(triangles[i] + vertPos);
                indices.push(triangles[i + 1] + vertPos);
                indices.push(triangles[i + 2] + vertPos);
            }
            for (var i = 0; i < points.length; i++) {
                verts.push(points[i]);
            }
        }
    },
};

/**
 * Builds a circle to draw
 *
 * Ignored from docs since it is not directly exposed.
 *
 * @ignore
 * @private
 * @param {WebGLGraphicsData} graphicsData - The graphics object to draw
 * @param {object} webGLData - an object containing all the WebGL-specific information to create this shape
 * @param {object} webGLDataNativeLines - an object containing all the WebGL-specific information to create nativeLines
 */
var buildCircle = {
    build: function (graphicsData) {
        // need to convert points to a nice regular data
        var circleData = graphicsData.shape;
        var points = graphicsData.points;
        var x = circleData.x;
        var y = circleData.y;
        var width;
        var height;
        points.length = 0;
        // TODO - bit hacky??
        if (graphicsData.type === SHAPES.CIRC) {
            width = circleData.radius;
            height = circleData.radius;
        }
        else {
            width = circleData.width;
            height = circleData.height;
        }
        if (width === 0 || height === 0) {
            return;
        }
        var totalSegs = Math.floor(30 * Math.sqrt(circleData.radius))
            || Math.floor(15 * Math.sqrt(width + height));
        totalSegs /= 2.3;
        var seg = (Math.PI * 2) / totalSegs;
        // for (let i = 0; i < totalSegs; i++) {
        //     points.push(
        //         x + (Math.sin(seg * i) * width),
        //         y + (Math.cos(seg * i) * height)
        //     );
        // }
        //20211220修改
        for (var i = 0; i < totalSegs - 0.5; i++) {
            points.push(//顺时针
            x + (Math.cos(seg * i) * width), y + (Math.sin(seg * i) * height));
        }
        points.push(points[0], points[1]);
    },
    triangulate: function (graphicsData, graphicsGeometry) {
        var points = graphicsData.points;
        var verts = graphicsGeometry.verts;
        var indices = graphicsGeometry.indices;
        var vertPos = verts.length / 2;
        var center = vertPos;
        verts.push(graphicsData.shape.x, graphicsData.shape.y);
        for (var i = 0; i < points.length; i += 2) {
            verts.push(points[i], points[i + 1]);
            // add some uvs
            indices.push(vertPos++, center, vertPos);
        }
    },
};

/**
 * Builds a rectangle to draw
 *
 * Ignored from docs since it is not directly exposed.
 *
 * @ignore
 * @private
 * @param {WebGLGraphicsData} graphicsData - The graphics object containing all the necessary properties
 * @param {object} webGLData - an object containing all the WebGL-specific information to create this shape
 * @param {object} webGLDataNativeLines - an object containing all the WebGL-specific information to create nativeLines
 */
var buildRectangle = {
    //计算点points
    build: function (graphicsData) {
        // --- //
        // need to convert points to a nice regular data
        //
        var rectData = graphicsData.shape;
        var x = rectData.x;
        var y = rectData.y;
        var width = rectData.width;
        var height = rectData.height;
        var points = graphicsData.points;
        points.length = 0;
        points.push(x, y, x + width, y, x + width, y + height, x, y + height);
    },
    //计算顶点和索引
    triangulate: function (graphicsData, graphics) {
        var points = graphicsData.points;
        //graphics之前可能已经有点
        var verts = graphics.verts;
        var vertPos = verts.length / 2;
        verts.push(points[0], points[1], points[2], points[3], points[6], points[7], points[4], points[5]);
        graphics.indices.push(vertPos, vertPos + 1, vertPos + 2, vertPos + 1, vertPos + 2, vertPos + 3);
    },
};

/**
 * Builds a rounded rectangle to draw
 *
 * Ignored from docs since it is not directly exposed.
 *
 * @ignore
 * @private
 * @param {WebGLGraphicsData} graphicsData - The graphics object containing all the necessary properties
 * @param {object} webGLData - an object containing all the WebGL-specific information to create this shape
 * @param {object} webGLDataNativeLines - an object containing all the WebGL-specific information to create nativeLines
 */
var buildRoundedRectangle = {
    build: function (graphicsData) {
        var rrectData = graphicsData.shape;
        var points = graphicsData.points;
        var x = rrectData.x;
        var y = rrectData.y;
        var width = rrectData.width;
        var height = rrectData.height;
        var radius = rrectData.radius;
        points.length = 0;
        // points.push(x, y + radius);
        // quadraticBezierCurve(x, y + height - radius, x, y + height, x + radius, y + height, points);
        // quadraticBezierCurve(x + width - radius, y + height, x + width, y + height, x + width, y + height - radius, points);
        // quadraticBezierCurve(x + width, y + radius, x + width, y, x + width - radius, y, points);
        // quadraticBezierCurve(x + radius, y, x, y, x, y + radius + 0.0000000001, points);
        // // this tiny number deals with the issue that occurs when points overlap and earcut fails to triangulate the item.
        // // TODO - fix this properly, this is not very elegant.. but it works for now.
        //20211212修改
        if (!radius) { //顺时针
            points.push(x, y, x + width, y, x + width, y + height, x, y + height);
        }
        else { //顺时针
            quadraticBezierCurve(x, y + radius, x, y, x + radius, y, points);
            quadraticBezierCurve(x + width - radius, y, x + width, y, x + width, y + radius, points);
            quadraticBezierCurve(x + width, y + height - radius, x + width, y + height, x + width - radius, y + height, points);
            quadraticBezierCurve(x + radius, y + height, x, y + height, x, y + height - radius, points);
        }
    },
    triangulate: function (graphicsData, graphicsGeometry) {
        var points = graphicsData.points;
        var verts = graphicsGeometry.verts;
        var indices = graphicsGeometry.indices;
        var vecPos = verts.length / 2;
        var triangles = earcut(points, null, 2);
        for (var i = 0, j = triangles.length; i < j; i += 3) {
            indices.push(triangles[i] + vecPos);
            //     indices.push(triangles[i] + vecPos);
            indices.push(triangles[i + 1] + vecPos);
            //   indices.push(triangles[i + 2] + vecPos);
            indices.push(triangles[i + 2] + vecPos);
        }
        for (var i = 0, j = points.length; i < j; i++) {
            verts.push(points[i], points[++i]);
        }
    },
};
/**
 * Calculate a single point for a quadratic bezier curve.
 * Utility function used by quadraticBezierCurve.
 * Ignored from docs since it is not directly exposed.
 *
 * @ignore
 * @private
 * @param {number} n1 - first number
 * @param {number} n2 - second number
 * @param {number} perc - percentage
 * @return {number} the result
 *
 */
function getPt(n1, n2, perc) {
    var diff = n2 - n1;
    return n1 + (diff * perc);
}
/**
 * Calculate the points for a quadratic bezier curve. (helper function..)
 * Based on: https://stackoverflow.com/questions/785097/how-do-i-implement-a-bezier-curve-in-c
 *
 * Ignored from docs since it is not directly exposed.
 *
 * @ignore
 * @private
 * @param {number} fromX - Origin point x
 * @param {number} fromY - Origin point x
 * @param {number} cpX - Control point x
 * @param {number} cpY - Control point y
 * @param {number} toX - Destination point x
 * @param {number} toY - Destination point y
 * @param {number[]} [out=[]] - The output array to add points into. If not passed, a new array is created.
 * @return {number[]} an array of points
 */
function quadraticBezierCurve(fromX, fromY, cpX, cpY, toX, toY, out) {
    if (out === void 0) { out = []; }
    var n = 20;
    var points = out;
    var xa = 0;
    var ya = 0;
    var xb = 0;
    var yb = 0;
    var x = 0;
    var y = 0;
    for (var i = 0, j = 0; i <= n; ++i) {
        j = i / n;
        // The Green Line
        xa = getPt(fromX, cpX, j);
        ya = getPt(fromY, cpY, j);
        xb = getPt(cpX, toX, j);
        yb = getPt(cpY, toY, j);
        // The Black Dot
        x = getPt(xa, xb, j);
        y = getPt(ya, yb, j);
        if (i === 0 && points[points.length - 2] === x && points[points.length - 1] === y) {
            continue;
        }
        points.push(x, y);
    }
    return points;
}

/**
 * Buffers vertices to draw a square cap.
 *
 * Ignored from docs since it is not directly exposed.
 *
 * @ignore
 * @private
 * @param {number} x - X-coord of end point
 * @param {number} y - Y-coord of end point
 * @param {number} nx - X-coord of line normal pointing inside
 * @param {number} ny - Y-coord of line normal pointing inside
 * @param {Array<number>} verts - vertex buffer
 * @returns {}
 */
function square(x, y, nx, ny, innerWeight, outerWeight, clockwise, /* rotation for square (true at left end, false at right end) */ verts) {
    var ix = x - (nx * innerWeight);
    var iy = y - (ny * innerWeight);
    var ox = x + (nx * outerWeight);
    var oy = y + (ny * outerWeight);
    /* Rotate nx,ny for extension vector */
    var exx;
    var eyy;
    if (clockwise) {
        exx = ny;
        eyy = -nx;
    }
    else {
        exx = -ny;
        eyy = nx;
    }
    /* [i|0]x,y extended at cap */
    var eix = ix + exx;
    var eiy = iy + eyy;
    var eox = ox + exx;
    var eoy = oy + eyy;
    /* Square itself must be inserted clockwise*/
    verts.push(eix, eiy);
    verts.push(eox, eoy);
    return 2;
}
/**
 * Buffers vertices to draw an arc at the line joint or cap.
 *
 * Ignored from docs since it is not directly exposed.
 *
 * @ignore
 * @private
 * @param {number} cx - X-coord of center
 * @param {number} cy - Y-coord of center
 * @param {number} sx - X-coord of arc start
 * @param {number} sy - Y-coord of arc start
 * @param {number} ex - X-coord of arc end
 * @param {number} ey - Y-coord of arc end
 * @param {Array<number>} verts - buffer of vertices
 * @param {boolean} clockwise - orientation of vertices
 * @returns {number} - no. of vertices pushed
 */
function round(cx, cy, sx, sy, ex, ey, verts, clockwise) {
    var cx2p0x = sx - cx;
    var cy2p0y = sy - cy;
    var angle0 = Math.atan2(cx2p0x, cy2p0y);
    var angle1 = Math.atan2(ex - cx, ey - cy);
    if (clockwise && angle0 < angle1) {
        angle0 += Math.PI * 2;
    }
    else if (!clockwise && angle0 > angle1) {
        angle1 += Math.PI * 2;
    }
    var startAngle = angle0;
    var angleDiff = angle1 - angle0;
    var absAngleDiff = Math.abs(angleDiff);
    /* if (absAngleDiff >= PI_LBOUND && absAngleDiff <= PI_UBOUND)
    {
        const r1x = cx - nxtPx;
        const r1y = cy - nxtPy;

        if (r1x === 0)
        {
            if (r1y > 0)
            {
                angleDiff = -angleDiff;
            }
        }
        else if (r1x >= -GRAPHICS_CURVES.epsilon)
        {
            angleDiff = -angleDiff;
        }
    }*/
    var radius = Math.sqrt((cx2p0x * cx2p0x) + (cy2p0y * cy2p0y));
    var segCount = ((15 * absAngleDiff * Math.sqrt(radius) / Math.PI) >> 0) + 1;
    var angleInc = angleDiff / segCount;
    startAngle += angleInc;
    if (clockwise) {
        verts.push(cx, cy);
        verts.push(sx, sy);
        for (var i = 1, angle = startAngle; i < segCount; i++, angle += angleInc) {
            verts.push(cx, cy);
            verts.push(cx + ((Math.sin(angle) * radius)), cy + ((Math.cos(angle) * radius)));
        }
        verts.push(cx, cy);
        verts.push(ex, ey);
    }
    else {
        verts.push(sx, sy);
        verts.push(cx, cy);
        for (var i = 1, angle = startAngle; i < segCount; i++, angle += angleInc) {
            verts.push(cx + ((Math.sin(angle) * radius)), cy + ((Math.cos(angle) * radius)));
            verts.push(cx, cy);
        }
        verts.push(ex, ey);
        verts.push(cx, cy);
    }
    return segCount * 2;
}
function buildNonNativeLine(graphicsData, graphicsGeometry) {
    var shape = graphicsData.shape;
    var points = graphicsData.points || shape.points.slice();
    var eps = graphicsGeometry.closePointEps;
    if (points.length === 0) {
        return;
    }
    // if the line width is an odd number add 0.5 to align to a whole pixel
    // commenting this out fixes #711 and #1620
    // if (graphicsData.lineWidth%2)
    // {
    //     for (i = 0; i < points.length; i++)
    //     {
    //         points[i] += 0.5;
    //     }
    // }
    var style = graphicsData.lineStyle;
    // get first and last point.. figure out the middle!
    var firstPoint = new Point(points[0], points[1]);
    var lastPoint = new Point(points[points.length - 2], points[points.length - 1]);
    var closedShape = shape.type !== SHAPES.POLY || shape.closed;
    var closedPath = Math.abs(firstPoint.x - lastPoint.x) < eps
        && Math.abs(firstPoint.y - lastPoint.y) < eps;
    // if the first point is the last point - gonna have issues :)
    if (closedShape) {
        // need to clone as we are going to slightly modify the shape..
        points = points.slice();
        if (closedPath) {
            points.pop();
            points.pop();
            lastPoint.set(points[points.length - 2], points[points.length - 1]);
        }
        var midPointX = (firstPoint.x + lastPoint.x) * 0.5;
        var midPointY = (lastPoint.y + firstPoint.y) * 0.5;
        points.unshift(midPointX, midPointY);
        points.push(midPointX, midPointY);
    }
    var verts = graphicsGeometry.verts;
    var length = points.length / 2;
    var indexCount = points.length;
    var indexStart = verts.length / 2;
    // Max. inner and outer width
    var width = style.width / 2;
    var widthSquared = width * width;
    var miterLimitSquared = style.miterLimit * style.miterLimit;
    /* Line segments of interest where (x1,y1) forms the corner. */
    var x0 = points[0];
    var y0 = points[1];
    var x1 = points[2];
    var y1 = points[3];
    var x2 = 0;
    var y2 = 0;
    /* perp[?](x|y) = the line normal with magnitude lineWidth. */
    var perpx = -(y0 - y1);
    var perpy = x0 - x1;
    var perp1x = 0;
    var perp1y = 0;
    var dist = Math.sqrt((perpx * perpx) + (perpy * perpy));
    perpx /= dist;
    perpy /= dist;
    perpx *= width;
    perpy *= width;
    var ratio = style.alignment; // 0.5;
    var innerWeight = (1 - ratio) * 2;
    var outerWeight = ratio * 2;
    if (!closedShape) {
        if (style.cap === LINE_CAP.ROUND) {
            indexCount += round(x0 - (perpx * (innerWeight - outerWeight) * 0.5), y0 - (perpy * (innerWeight - outerWeight) * 0.5), x0 - (perpx * innerWeight), y0 - (perpy * innerWeight), x0 + (perpx * outerWeight), y0 + (perpy * outerWeight), verts, true) + 2;
        }
        else if (style.cap === LINE_CAP.SQUARE) {
            indexCount += square(x0, y0, perpx, perpy, innerWeight, outerWeight, true, verts);
        }
    }
    // Push first point (below & above vertices)
    verts.push(x0 - (perpx * innerWeight), y0 - (perpy * innerWeight));
    verts.push(x0 + (perpx * outerWeight), y0 + (perpy * outerWeight));
    for (var i = 1; i < length - 1; ++i) {
        x0 = points[(i - 1) * 2];
        y0 = points[((i - 1) * 2) + 1];
        x1 = points[i * 2];
        y1 = points[(i * 2) + 1];
        x2 = points[(i + 1) * 2];
        y2 = points[((i + 1) * 2) + 1];
        perpx = -(y0 - y1);
        perpy = x0 - x1;
        dist = Math.sqrt((perpx * perpx) + (perpy * perpy));
        perpx /= dist;
        perpy /= dist;
        perpx *= width;
        perpy *= width;
        perp1x = -(y1 - y2);
        perp1y = x1 - x2;
        dist = Math.sqrt((perp1x * perp1x) + (perp1y * perp1y));
        perp1x /= dist;
        perp1y /= dist;
        perp1x *= width;
        perp1y *= width;
        /* d[x|y](0|1) = the component displacement between points p(0,1|1,2) */
        var dx0 = x1 - x0;
        var dy0 = y0 - y1;
        var dx1 = x1 - x2;
        var dy1 = y2 - y1;
        /* +ve if internal angle counterclockwise, -ve if internal angle clockwise. */
        var cross = (dy0 * dx1) - (dy1 * dx0);
        var clockwise = (cross < 0);
        /* Going nearly straight? */
        if (Math.abs(cross) < 0.1) {
            verts.push(x1 - (perpx * innerWeight), y1 - (perpy * innerWeight));
            verts.push(x1 + (perpx * outerWeight), y1 + (perpy * outerWeight));
            continue;
        }
        /* p[x|y] is the miter point. pdist is the distance between miter point and p1. */
        var c1 = ((-perpx + x0) * (-perpy + y1)) - ((-perpx + x1) * (-perpy + y0));
        var c2 = ((-perp1x + x2) * (-perp1y + y1)) - ((-perp1x + x1) * (-perp1y + y2));
        var px = ((dx0 * c2) - (dx1 * c1)) / cross;
        var py = ((dy1 * c1) - (dy0 * c2)) / cross;
        var pdist = ((px - x1) * (px - x1)) + ((py - y1) * (py - y1));
        /* Inner miter point */
        var imx = x1 + ((px - x1) * innerWeight);
        var imy = y1 + ((py - y1) * innerWeight);
        /* Outer miter point */
        var omx = x1 - ((px - x1) * outerWeight);
        var omy = y1 - ((py - y1) * outerWeight);
        /* Is the inside miter point too far away, creating a spike? */
        var smallerInsideSegmentSq = Math.min((dx0 * dx0) + (dy0 * dy0), (dx1 * dx1) + (dy1 * dy1));
        var insideWeight = clockwise ? innerWeight : outerWeight;
        var smallerInsideDiagonalSq = smallerInsideSegmentSq + (insideWeight * insideWeight * widthSquared);
        var insideMiterOk = pdist <= smallerInsideDiagonalSq;
        if (insideMiterOk) {
            if (style.join === LINE_JOIN.BEVEL || pdist / widthSquared > miterLimitSquared) {
                if (clockwise) /* rotating at inner angle */ {
                    verts.push(imx, imy); // inner miter point
                    verts.push(x1 + (perpx * outerWeight), y1 + (perpy * outerWeight)); // first segment's outer vertex
                    verts.push(imx, imy); // inner miter point
                    verts.push(x1 + (perp1x * outerWeight), y1 + (perp1y * outerWeight)); // second segment's outer vertex
                }
                else /* rotating at outer angle */ {
                    verts.push(x1 - (perpx * innerWeight), y1 - (perpy * innerWeight)); // first segment's inner vertex
                    verts.push(omx, omy); // outer miter point
                    verts.push(x1 - (perp1x * innerWeight), y1 - (perp1y * innerWeight)); // second segment's outer vertex
                    verts.push(omx, omy); // outer miter point
                }
                indexCount += 2;
            }
            else if (style.join === LINE_JOIN.ROUND) {
                if (clockwise) /* arc is outside */ {
                    verts.push(imx, imy);
                    verts.push(x1 + (perpx * outerWeight), y1 + (perpy * outerWeight));
                    indexCount += round(x1, y1, x1 + (perpx * outerWeight), y1 + (perpy * outerWeight), x1 + (perp1x * outerWeight), y1 + (perp1y * outerWeight), verts, true) + 4;
                    verts.push(imx, imy);
                    verts.push(x1 + (perp1x * outerWeight), y1 + (perp1y * outerWeight));
                }
                else /* arc is inside */ {
                    verts.push(x1 - (perpx * innerWeight), y1 - (perpy * innerWeight));
                    verts.push(omx, omy);
                    indexCount += round(x1, y1, x1 - (perpx * innerWeight), y1 - (perpy * innerWeight), x1 - (perp1x * innerWeight), y1 - (perp1y * innerWeight), verts, false) + 4;
                    verts.push(x1 - (perp1x * innerWeight), y1 - (perp1y * innerWeight));
                    verts.push(omx, omy);
                }
            }
            else {
                verts.push(imx, imy);
                verts.push(omx, omy);
            }
        }
        else // inside miter is NOT ok
         {
            verts.push(x1 - (perpx * innerWeight), y1 - (perpy * innerWeight)); // first segment's inner vertex
            verts.push(x1 + (perpx * outerWeight), y1 + (perpy * outerWeight)); // first segment's outer vertex
            if (style.join === LINE_JOIN.BEVEL || pdist / widthSquared > miterLimitSquared) ;
            else if (style.join === LINE_JOIN.ROUND) {
                if (clockwise) /* arc is outside */ {
                    indexCount += round(x1, y1, x1 + (perpx * outerWeight), y1 + (perpy * outerWeight), x1 + (perp1x * outerWeight), y1 + (perp1y * outerWeight), verts, true) + 2;
                }
                else /* arc is inside */ {
                    indexCount += round(x1, y1, x1 - (perpx * innerWeight), y1 - (perpy * innerWeight), x1 - (perp1x * innerWeight), y1 - (perp1y * innerWeight), verts, false) + 2;
                }
            }
            else {
                if (clockwise) {
                    verts.push(omx, omy); // inner miter point
                    verts.push(omx, omy); // inner miter point
                }
                else {
                    verts.push(imx, imy); // outer miter point
                    verts.push(imx, imy); // outer miter point
                }
                indexCount += 2;
            }
            verts.push(x1 - (perp1x * innerWeight), y1 - (perp1y * innerWeight)); // second segment's inner vertex
            verts.push(x1 + (perp1x * outerWeight), y1 + (perp1y * outerWeight)); // second segment's outer vertex
            indexCount += 2;
        }
    }
    x0 = points[(length - 2) * 2];
    y0 = points[((length - 2) * 2) + 1];
    x1 = points[(length - 1) * 2];
    y1 = points[((length - 1) * 2) + 1];
    perpx = -(y0 - y1);
    perpy = x0 - x1;
    dist = Math.sqrt((perpx * perpx) + (perpy * perpy));
    perpx /= dist;
    perpy /= dist;
    perpx *= width;
    perpy *= width;
    verts.push(x1 - (perpx * innerWeight), y1 - (perpy * innerWeight));
    verts.push(x1 + (perpx * outerWeight), y1 + (perpy * outerWeight));
    if (!closedShape) {
        if (style.cap === LINE_CAP.ROUND) {
            indexCount += round(x1 - (perpx * (innerWeight - outerWeight) * 0.5), y1 - (perpy * (innerWeight - outerWeight) * 0.5), x1 - (perpx * innerWeight), y1 - (perpy * innerWeight), x1 + (perpx * outerWeight), y1 + (perpy * outerWeight), verts, false) + 2;
        }
        else if (style.cap === LINE_CAP.SQUARE) {
            indexCount += square(x1, y1, perpx, perpy, innerWeight, outerWeight, false, verts);
        }
    }
    var indices = graphicsGeometry.indices;
    var eps2 = eps * eps;
    // indices.push(indexStart);
    for (var i = indexStart; i < indexCount + indexStart - 2; ++i) {
        x0 = verts[(i * 2)];
        y0 = verts[(i * 2) + 1];
        x1 = verts[(i + 1) * 2];
        y1 = verts[((i + 1) * 2) + 1];
        x2 = verts[(i + 2) * 2];
        y2 = verts[((i + 2) * 2) + 1];
        /* Skip zero area triangles */
        if (Math.abs((x0 * (y1 - y2)) + (x1 * (y2 - y0)) + (x2 * (y0 - y1))) < eps2) {
            continue;
        }
        indices.push(i, i + 1, i + 2);
    }
}
function buildLine(graphicsData, graphicsGeometry) {
    // if (graphicsData.lineStyle.native) {
    //     buildNativeLine(graphicsData, graphicsGeometry);
    // }
    // else {
    buildNonNativeLine(graphicsData, graphicsGeometry);
    // }
}

/**
 * 图形的填充形式
 * @class
 */
var FillStyle = /** @class */ (function () {
    function FillStyle() {
        this.reset();
    }
    FillStyle.prototype.clone = function () {
        var obj = new FillStyle();
        obj.color = this.color;
        obj.alpha = this.alpha;
        obj.texture = this.texture;
        obj.matrix = this.matrix;
        obj.visible = this.visible;
        obj.alphaBlock = this.alphaBlock;
        return obj;
    };
    /**
     * 重置
     */
    FillStyle.prototype.reset = function () {
        this.color = 0xFFFFFF;
        this.alpha = 1;
        this.texture = Texture.WHITE;
        this.matrix = null;
        this.visible = false;
        //
        this.alphaBlock = false;
    };
    /**
     * 销毁
     */
    FillStyle.prototype.destroy = function () {
        this.texture = null;
        this.matrix = null;
    };
    return FillStyle;
}());

/**
 * 图形的画线模式
 */
var LineStyle = /** @class */ (function (_super) {
    __extends(LineStyle, _super);
    function LineStyle() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        /**
         * Line cap style.
         * @default LINE_CAP.BUTT
         */
        _this.cap = LINE_CAP.BUTT;
        /**
         * Line join style.
         * @default LINE_JOIN.MITER
         */
        _this.join = LINE_JOIN.MITER;
        /**
         * Miter limit.
         */
        _this.miterLimit = 10;
        return _this;
    }
    /**
     * Clones the object
     *
     * @return {LineStyle}
     */
    LineStyle.prototype.clone = function () {
        var obj = new LineStyle();
        obj.color = this.color;
        obj.alpha = this.alpha;
        obj.texture = this.texture;
        obj.matrix = this.matrix;
        obj.visible = this.visible;
        obj.width = this.width;
        obj.alignment = this.alignment;
        obj.native = this.native;
        obj.cap = this.cap;
        obj.join = this.join;
        obj.miterLimit = this.miterLimit;
        return obj;
    };
    /**
     * 重置
     */
    LineStyle.prototype.reset = function () {
        _super.prototype.reset.call(this);
        // 默认黑色0x000000
        this.color = 0x0;
        this.width = 0;
        this.alignment = 0.5;
        this.native = false;
        this.cap = LINE_CAP.BUTT;
        this.join = LINE_JOIN.MITER;
        this.miterLimit = 10;
    };
    return LineStyle;
}(FillStyle));

/**
 * Calculate the points for a bezier curve and then draws it.
 *
 * Ignored from docs since it is not directly exposed.
 *
 * @ignore
 * @param {number} fromX - Starting point x
 * @param {number} fromY - Starting point y
 * @param {number} cpX - Control point x
 * @param {number} cpY - Control point y
 * @param {number} cpX2 - Second Control point x
 * @param {number} cpY2 - Second Control point y
 * @param {number} toX - Destination point x
 * @param {number} toY - Destination point y
 * @param {number} n - Number of segments approximating the bezier curve
 * @param {number[]} [path=[]] - Path array to push points into
 * @return {number[]} Array of points of the curve
 */
function bezierCurveTo(fromX, fromY, cpX, cpY, cpX2, cpY2, toX, toY, n, path) {
    if (path === void 0) { path = []; }
    var dt = 0;
    var dt2 = 0;
    var dt3 = 0;
    var t2 = 0;
    var t3 = 0;
    path.push(fromX, fromY);
    for (var i = 1, j = 0; i <= n; ++i) {
        j = i / n;
        dt = (1 - j);
        dt2 = dt * dt;
        dt3 = dt2 * dt;
        t2 = j * j;
        t3 = t2 * j;
        path.push((dt3 * fromX) + (3 * dt2 * j * cpX) + (3 * dt * t2 * cpX2) + (t3 * toX), (dt3 * fromY) + (3 * dt2 * j * cpY) + (3 * dt * t2 * cpY2) + (t3 * toY));
    }
    return path;
}

/**
 * Graphics curves resolution settings. If `adaptive` flag is set to `true`,
 * the resolution is calculated based on the curve's length to ensure better visual quality.
 * Adaptive draw works with `bezierCurveTo` and `quadraticCurveTo`.
 *
 * @constant
 * @name CURVES
 * @type {object}
 * @property {boolean} adaptive=false - flag indicating if the resolution should be adaptive
 * @property {number} maxLength=10 - maximal length of a single segment of the curve (if adaptive = false, ignored)
 * @property {number} minSegments=8 - minimal number of segments in the curve (if adaptive = false, ignored)
 * @property {number} maxSegments=2048 - maximal number of segments in the curve (if adaptive = false, ignored)
 */
var GRAPHICS_CURVES = {
    adaptive: false,
    maxLength: 10,
    minSegments: 8,
    maxSegments: 2048,
    /**
     * 根据曲线长度给出分段数，保证光滑
     *
     * @private
     * @param {number} length 曲线长度
     * @param {number} defaultSegments 默认分段数
     * @return {number} 分段数
     */
    segmentsCount: function (length, defaultSegments) {
        if (defaultSegments === void 0) { defaultSegments = 20; }
        if (!this.adaptive)
            return defaultSegments;
        var result = Math.ceil(length / this.maxLength);
        if (result < this.minSegments) {
            result = this.minSegments;
        }
        else if (result > this.maxSegments) {
            result = this.maxSegments;
        }
        return result;
    }
};
/**
 * Calculate length of quadratic curve
 * @see {@link http://www.malczak.linuxpl.com/blog/quadratic-bezier-curve-length/}
 * for the detailed explanation of math behind this.
 *
 * @param {number} fromX - x-coordinate of curve start point
 * @param {number} fromY - y-coordinate of curve start point
 * @param {number} cpX - x-coordinate of curve control point
 * @param {number} cpY - y-coordinate of curve control point
 * @param {number} toX - x-coordinate of curve end point
 * @param {number} toY - y-coordinate of curve end point
 * @return {number} Length of quadratic curve
 */
function quadraticCurveLength(fromX, fromY, cpX, cpY, toX, toY) {
    var ax = fromX - ((2.0 * cpX) + toX);
    var ay = fromY - ((2.0 * cpY) + toY);
    var bx = 2.0 * ((cpX - 2.0) * fromX);
    var by = 2.0 * ((cpY - 2.0) * fromY);
    var a = 4.0 * ((ax * ax) + (ay * ay));
    var b = 4.0 * ((ax * bx) + (ay * by));
    var c = (bx * bx) + (by * by);
    var s = 2.0 * Math.sqrt(a + b + c);
    var a2 = Math.sqrt(a);
    var a32 = 2.0 * a * a2;
    var c2 = 2.0 * Math.sqrt(c);
    var ba = b / a2;
    return ((a32 * s)
        + (a2 * b * (s - c2))
        + (((4.0 * c * a) - (b * b))
            * Math.log(((2.0 * a2) + ba + s) / (ba + c2))))
        / (4.0 * a32);
}
/**
 * Calculate length of bezier curve.
 * Analytical solution is impossible, since it involves an integral that does not integrate in general.
 * Therefore numerical solution is used.
 *
 * @param {number} fromX - Starting point x
 * @param {number} fromY - Starting point y
 * @param {number} cpX - Control point x
 * @param {number} cpY - Control point y
 * @param {number} cpX2 - Second Control point x
 * @param {number} cpY2 - Second Control point y
 * @param {number} toX - Destination point x
 * @param {number} toY - Destination point y
 * @return {number} Length of bezier curve
 */
function bezierCurveLength(fromX, fromY, cpX, cpY, cpX2, cpY2, toX, toY) {
    var n = 10;
    var result = 0.0;
    var t = 0.0;
    var t2 = 0.0;
    var t3 = 0.0;
    var nt = 0.0;
    var nt2 = 0.0;
    var nt3 = 0.0;
    var x = 0.0;
    var y = 0.0;
    var dx = 0.0;
    var dy = 0.0;
    var prevX = fromX;
    var prevY = fromY;
    for (var i = 1; i <= n; ++i) {
        t = i / n;
        t2 = t * t;
        t3 = t2 * t;
        nt = (1.0 - t);
        nt2 = nt * nt;
        nt3 = nt2 * nt;
        x = (nt3 * fromX) + (3.0 * nt2 * t * cpX) + (3.0 * nt * t2 * cpX2) + (t3 * toX);
        y = (nt3 * fromY) + (3.0 * nt2 * t * cpY) + (3 * nt * t2 * cpY2) + (t3 * toY);
        dx = prevX - x;
        dy = prevY - y;
        prevX = x;
        prevY = y;
        result += Math.sqrt((dx * dx) + (dy * dy));
    }
    return result;
}

var canvasRenderer;
var tempMatrix$3 = new Matrix();
var tempPoint$2 = new Point();
//公用颜色rgb
var temp = new Float32Array(3);
//geoBatchPart对象池
var GEOBATCH_POOL = [];
//分割三角指令托管
var fillCommands = {};
fillCommands[SHAPES.POLY] = buildPoly;
fillCommands[SHAPES.CIRC] = buildCircle;
fillCommands[SHAPES.ELIP] = buildCircle;
fillCommands[SHAPES.RECT] = buildRectangle;
fillCommands[SHAPES.RREC] = buildRoundedRectangle;
/**
 * @class Graphics
 * 自身matrix无效，暂时不用
 * style的纹理matrix无效，暂时不用
 * 最终都会按照三角形数据存储，包括画面和画线
 * 对于持续画线之类的画板。画越多记录的数据越多，建议用Shape（直接一张离屏缓存），
 */
var Graphics = /** @class */ (function (_super) {
    __extends(Graphics, _super);
    function Graphics() {
        var _this = _super.call(this) || this;
        /**
         * 混色模式
         * @default BLEND_MODES.NORMAL
         */
        _this._blendMode = BLEND_MODES.NORMAL;
        /**
         * 判断是否更新色值
         */
        _this.batchTint = -1;
        _this.hitTestByPixel = true;
        /**
         * canvas必用缓存
         * renderCanvas默认用缓存,也就canvas上使用，如果经常需要重绘，设置为false
         * webgl上用贴图占用GPU空间太大，用其他方法实现,贴图是白图就一张，用几何方法实现
         * @name cacheAsBitmap
         * @member {boolean}
         * @memberof Graphics#
         * @default false
         */
        _this.cacheAsBitmap = true;
        // //如果用缓存绘图，必须考虑偏移量；，直接使用_localBoundsSelf.xy
        // offsetX: number;
        // offsetY: number;
        /**
         * Minimal distance between points that are considered different.
         * Affects line tesselation.
         */
        _this.closePointEps = 1e-4;
        _this._instanceType = "Graphics";
        _this._fillStyle = new FillStyle();
        _this._lineStyle = new LineStyle();
        _this.tint = 0xFFFFFF;
        _this.batchTint = -1;
        _this._matrix = null;
        _this._holeMode = false;
        _this._currentPath = null;
        _this.graphicsData = [];
        _this._isUsedToMask = false;
        _this.boundsPadding = 0;
        _this.dirty = 0;
        _this.boundsDirty = -1;
        _this.cacheDirty = -1;
        _this.verts = [];
        _this.indices = [];
        _this.batches = [];
        _this.geoBatches = [];
        _this.uvs = [];
        _this.batchDirty = -1;
        _this.shapeIndex = 0;
        _this.vertexData = null;
        _this._transformID = -1;
        return _this;
    }
    Object.defineProperty(Graphics.prototype, "blendMode", {
        //以后修改，估计需要标记，用来修改batch，否则可能无效
        get: function () {
            return this._blendMode;
        },
        /**
         * 很多效果暂时无效，再查原因，先不能设置吧
         */
        set: function (value) {
            // if (value != this._blendMode) this._blendMode = value
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Graphics.prototype, "fill", {
        /**
         * @member {FillStyle}
         * @readonly
         */
        get: function () {
            return this._fillStyle;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Graphics.prototype, "line", {
        /**
         * @member {LineStyle}
         * @readonly
         */
        get: function () {
            return this._lineStyle;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Graphics.prototype, "tint", {
        get: function () {
            return this._tint;
        },
        set: function (value) {
            this._tint = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Graphics.prototype, "matrix", {
        get: function () {
            return this._matrix;
        },
        set: function (matrix) {
            //暂时不用
            // this._matrix = matrix;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 克隆该Graphics的几何绘制，不包括它自身的transform
     * @return {Graphics}
     */
    Graphics.prototype.clone = function () {
        var clone = new Graphics();
        clone.renderable = this.renderable;
        clone._fillStyle = this._fillStyle;
        clone._lineStyle = this._lineStyle;
        clone._isUsedToMask = this._isUsedToMask;
        clone.boundsPadding = this.boundsPadding;
        clone.dirty = 0;
        for (var i = 0; i < this.graphicsData.length; ++i) {
            clone.graphicsData.push(this.graphicsData[i].clone());
        }
        //考虑当前路径是否置空
        clone._currentPath = null;
        // clone._currentPath = clone.graphicsData[clone.graphicsData.length - 1];
        clone.updateLocalBoundsSelf();
        return clone;
    };
    /**
     * 为了有一个和Shape保持一致的方法，也为了能加入cap等属性，但不改变原来的lineStyle
     * 比Shape多了aligment方法，和native（暂时无效）
     * @param color
     * @param lineWidth
     * @param cap
     * @param join
     * @param miterLimit
     * @param alpha
     * @param alignment - 线的居中方式，注意对于多边形，永远是朝向的左边为1，右边为0，封闭时顺时针外部1内部0，逆时针相反，canvas模式下暂时只有居中0.5
     * @param native
     */
    Graphics.prototype.beginStroke = function (color, lineWidth, cap, join, miterLimit, alpha, alignment, native) {
        if (color === void 0) { color = 0; }
        if (lineWidth === void 0) { lineWidth = 1; }
        if (cap === void 0) { cap = LINE_CAP.BUTT; }
        if (join === void 0) { join = LINE_JOIN.MITER; }
        if (miterLimit === void 0) { miterLimit = 10; }
        if (alpha === void 0) { alpha = 1; }
        if (alignment === void 0) { alignment = 0.5; }
        if (native === void 0) { native = false; }
        //兼容下颜色格式
        if (typeof (color) == "string")
            color = string2hex(color);
        this.lineTextureStyle(lineWidth, Texture.WHITE, color, alpha, null, alignment, native);
        //三个属性
        this._lineStyle.cap = cap;
        this._lineStyle.join = join;
        this._lineStyle.miterLimit = miterLimit;
        return this;
    };
    /**
     * line属于附属属性，暂不写beginStroke，只要没调用过beginFill就是纯stroke
     * @param {number} [lineWidth=0] - 线的粗细
     * @param {number} [color=0] - 线的颜色
     * @param {number} [alpha=1] - 线的透明度
     * @param {number} [alignment=0.5] - 线的居中方式，注意对于多边形，永远是朝向的左边为1，右边为0，封闭时顺时针外部1内部0，逆时针相反，canvas模式下暂时只有居中0.5
     * @return {Graphics}
     */
    Graphics.prototype.lineStyle = function (lineWidth, color, alpha, alignment, native) {
        if (lineWidth === void 0) { lineWidth = 0; }
        if (color === void 0) { color = 0; }
        if (alpha === void 0) { alpha = 1; }
        if (alignment === void 0) { alignment = 0.5; }
        if (native === void 0) { native = false; }
        this.lineTextureStyle(lineWidth, Texture.WHITE, color, alpha, null, alignment, native);
        return this;
    };
    Graphics.prototype.lineTextureStyle = function (width, texture, color, alpha, matrix, alignment, native) {
        if (width === void 0) { width = 0; }
        if (texture === void 0) { texture = Texture.WHITE; }
        if (color === void 0) { color = 0xFFFFFF; }
        if (alpha === void 0) { alpha = 1; }
        if (matrix === void 0) { matrix = null; }
        if (alignment === void 0) { alignment = 0.5; }
        if (native === void 0) { native = false; }
        if (this._currentPath)
            this.startPoly();
        var visible = width > 0 && alpha > 0;
        if (!visible) {
            this._lineStyle.reset();
        }
        else {
            if (matrix) {
                matrix = matrix.clone();
                matrix.invert();
            }
            this._lineStyle.color = color;
            this._lineStyle.width = width;
            this._lineStyle.alpha = alpha;
            this._lineStyle.matrix = matrix;
            this._lineStyle.texture = texture;
            this._lineStyle.alignment = alignment;
            this._lineStyle.native = native;
            this._lineStyle.visible = visible;
            // Object.assign(this._lineStyle, {
            //     color,
            //     width,
            //     alpha,
            //     matrix,
            //     texture,
            //     alignment,
            //     native,
            //     visible,
            // });
        }
        return this;
    };
    Graphics.prototype.startPoly = function () {
        if (this._currentPath) {
            var points = this._currentPath.points;
            var len = this._currentPath.points.length;
            if (len > 2) {
                this.drawShape(this._currentPath);
                this._currentPath = new Polygon();
                this._currentPath.closed = false;
                this._currentPath.points.push(points[len - 2], points[len - 1]);
            }
        }
        else {
            this._currentPath = new Polygon();
            this._currentPath.closed = false;
        }
    };
    Graphics.prototype.finishPoly = function () {
        if (this._currentPath) {
            if (this._currentPath.points.length > 2) {
                this.drawShape(this._currentPath);
                this._currentPath = null;
            }
            else {
                this._currentPath.points.length = 0;
            }
        }
    };
    Graphics.prototype.moveTo = function (x, y) {
        this.startPoly();
        this._currentPath.points[0] = x;
        this._currentPath.points[1] = y;
        return this;
    };
    Graphics.prototype.lineTo = function (x, y) {
        if (!this._currentPath)
            this.moveTo(0, 0);
        // remove duplicates..
        var points = this._currentPath.points;
        var fromX = points[points.length - 2];
        var fromY = points[points.length - 1];
        if (fromX !== x || fromY !== y) {
            points.push(x, y);
        }
        return this;
    };
    /**
     * 初始化曲线
     * @param x
     * @param y
     */
    Graphics.prototype._initCurve = function (x, y) {
        if (x === void 0) { x = 0; }
        if (y === void 0) { y = 0; }
        if (this._currentPath) {
            if (this._currentPath.points.length === 0) {
                this._currentPath.points = [x, y];
            }
        }
        else {
            this.moveTo(x, y);
        }
    };
    /**
     * 二次贝塞尔曲线
     * @param {number} cpX - 控制点x
     * @param {number} cpY - 控制点y
     * @param {number} toX - 目标点x
     * @param {number} toY - 目标点y
     * @return {Graphics} 返回自身
     */
    Graphics.prototype.quadraticCurveTo = function (cpX, cpY, toX, toY) {
        this._initCurve();
        var points = this._currentPath.points;
        if (points.length === 0) {
            this.moveTo(0, 0);
        }
        var xa = 0;
        var ya = 0;
        var fromX = points[points.length - 2];
        var fromY = points[points.length - 1];
        var n = GRAPHICS_CURVES.segmentsCount(quadraticCurveLength(fromX, fromY, cpX, cpY, toX, toY));
        for (var i = 1; i <= n; ++i) {
            var j = i / n;
            xa = fromX + ((cpX - fromX) * j);
            ya = fromY + ((cpY - fromY) * j);
            points.push(xa + (((cpX + ((toX - cpX) * j)) - xa) * j), ya + (((cpY + ((toY - cpY) * j)) - ya) * j));
        }
        return this;
    };
    /**
     * 三次贝塞尔曲线
     * @param {number} cpX - 第一控制点x
     * @param {number} cpY - 第一控制点y
     * @param {number} cpX2 - 第二控制点x
     * @param {number} cpY2 - 第二控制点y
     * @param {number} toX - 目标点x
     * @param {number} toY - 目标点y
     * @return {Graphics} 返回自身
     */
    Graphics.prototype.bezierCurveTo = function (cpX, cpY, cpX2, cpY2, toX, toY) {
        this._initCurve();
        var points = this._currentPath.points;
        var fromX = points[points.length - 2];
        var fromY = points[points.length - 1];
        points.length -= 2;
        var n = GRAPHICS_CURVES.segmentsCount(bezierCurveLength(fromX, fromY, cpX, cpY, cpX2, cpY2, toX, toY));
        bezierCurveTo(fromX, fromY, cpX, cpY, cpX2, cpY2, toX, toY, n, points);
        return this;
    };
    /**
     * 根据两切线绘制弧线
     * @param {number} x1 - 起始切点x
     * @param {number} y1 - 起始切点y
     * @param {number} x2 - 结束切点x
     * @param {number} y2 - 结束切点y
     * @param {number} radius - 半径
     * @return {Graphics} 返回自身
     */
    Graphics.prototype.arcTo = function (x1, y1, x2, y2, radius) {
        this._initCurve(x1, y1);
        var points = this._currentPath.points;
        var fromX = points[points.length - 2];
        var fromY = points[points.length - 1];
        var a1 = fromY - y1;
        var b1 = fromX - x1;
        var a2 = y2 - y1;
        var b2 = x2 - x1;
        var mm = Math.abs((a1 * b2) - (b1 * a2));
        if (mm < 1.0e-8 || radius === 0) {
            if (points[points.length - 2] !== x1 || points[points.length - 1] !== y1) {
                points.push(x1, y1);
            }
        }
        else {
            var dd = (a1 * a1) + (b1 * b1);
            var cc = (a2 * a2) + (b2 * b2);
            var tt = (a1 * a2) + (b1 * b2);
            var k1 = radius * Math.sqrt(dd) / mm;
            var k2 = radius * Math.sqrt(cc) / mm;
            var j1 = k1 * tt / dd;
            var j2 = k2 * tt / cc;
            var cx = (k1 * b2) + (k2 * b1);
            var cy = (k1 * a2) + (k2 * a1);
            var px = b1 * (k2 + j1);
            var py = a1 * (k2 + j1);
            var qx = b2 * (k1 + j2);
            var qy = a2 * (k1 + j2);
            var startAngle = Math.atan2(py - cy, px - cx);
            var endAngle = Math.atan2(qy - cy, qx - cx);
            this.arc(cx + x1, cy + y1, radius, startAngle, endAngle, b1 * a2 > b2 * a1);
        }
        return this;
    };
    /**
     * 创建圆弧
     * 详见https://www.runoob.com/jsref/met-canvas-arc.html
     * @param {number} cx - 圆弧中心x
     * @param {number} cy - 圆弧中心y
     * @param {number} radius - 圆弧半径
     * @param {number} startAngle - 开始角度，0为三点钟位置
     * @param {number} endAngle - 结束角度
     * @param {boolean} [anticlockwise=false] - true为逆时针，false为顺时针，默认false
     * @return {Graphics}
     */
    Graphics.prototype.arc = function (cx, cy, radius, startAngle, endAngle, anticlockwise) {
        if (anticlockwise === void 0) { anticlockwise = false; }
        if (startAngle === endAngle) {
            return this;
        }
        if (!anticlockwise && endAngle <= startAngle) {
            endAngle += PI_2;
        }
        else if (anticlockwise && startAngle <= endAngle) {
            startAngle += PI_2;
        }
        var sweep = endAngle - startAngle;
        if (sweep === 0) {
            return this;
        }
        var startX = cx + (Math.cos(startAngle) * radius);
        var startY = cy + (Math.sin(startAngle) * radius);
        var eps = this.closePointEps;
        // If the _currentPath exists, take its points. Otherwise call `moveTo` to start a path.
        var points = this._currentPath ? this._currentPath.points : null;
        if (points) {
            // We check how far our start is from the last existing point
            var xDiff = Math.abs(points[points.length - 2] - startX);
            var yDiff = Math.abs(points[points.length - 1] - startY);
            if (xDiff < eps && yDiff < eps) ;
            else {
                points.push(startX, startY);
            }
        }
        else {
            this.moveTo(startX, startY);
            points = this._currentPath.points;
        }
        var segs = GRAPHICS_CURVES.segmentsCount(Math.abs(sweep) * radius, Math.ceil(Math.abs(sweep) / PI_2) * 40);
        var theta = sweep / (segs * 2);
        var theta2 = theta * 2;
        var cTheta = Math.cos(theta);
        var sTheta = Math.sin(theta);
        var segMinus = segs - 1;
        var remainder = (segMinus % 1) / segMinus;
        for (var i = 0; i <= segMinus; ++i) {
            var real = i + (remainder * i);
            var angle = ((theta) + startAngle + (theta2 * real));
            var c = Math.cos(angle);
            var s = -Math.sin(angle);
            points.push((((cTheta * c) + (sTheta * s)) * radius) + cx, (((cTheta * -s) + (sTheta * c)) * radius) + cy);
        }
        return this;
    };
    /**
     * 设置开始填充属性
     * @param {number | string} [color=0] - 十六进制颜色0xffffff
     * @param {number} [alpha=1] - 绘制透明度
     * @return {Graphics}
     */
    Graphics.prototype.beginFill = function (color, alpha) {
        if (color === void 0) { color = 0; }
        if (alpha === void 0) { alpha = 1; }
        //颜色做个兼容吧
        if (typeof (color) == "string")
            color = string2hex(color);
        return this.beginTextureFill(Texture.WHITE, color, alpha);
    };
    Graphics.prototype.beginTextureFill = function (texture, color, alpha, matrix) {
        if (texture === void 0) { texture = Texture.WHITE; }
        if (color === void 0) { color = 0xFFFFFF; }
        if (alpha === void 0) { alpha = 1; }
        if (matrix === void 0) { matrix = null; }
        if (this._currentPath)
            this.startPoly();
        var visible = alpha > 0;
        if (!visible) {
            this._fillStyle.reset();
            //需要额外加参数
            this._fillStyle.alphaBlock = true;
        }
        else {
            this._fillStyle.color = color;
            this._fillStyle.alpha = alpha;
            this._fillStyle.texture = texture;
            this._fillStyle.matrix = matrix;
            this._fillStyle.visible = visible;
            // Object.assign(this._fillStyle, {
            //     color,
            //     alpha,
            //     texture,
            //     matrix,
            //     visible,
            // });
        }
        return this;
    };
    /**
     * 结束填充
     * @return {Graphics}
     */
    Graphics.prototype.endFill = function () {
        this.finishPoly();
        this._fillStyle.reset();
        return this;
    };
    /**
     * 结束线段
     * @return {Graphics}
     */
    Graphics.prototype.endStroke = function () {
        this.finishPoly();
        this._lineStyle.reset();
        return this;
    };
    /**
     * 闭合路径，只为了画线stroke时确定是否闭合，终点和起点一致也不能算闭合，只有调用时算，fill没必要
     * 只用在多边形的路径里
     * @return {Graphics}
     */
    Graphics.prototype.closePath = function () {
        //如果下个可能要画洞，先闭合之前的路径
        var _currentPath = this._currentPath;
        if (this._currentPath)
            _currentPath.closed = true; //_currentPath.close();
        return this;
    };
    /**
     * 开始画洞
     */
    Graphics.prototype.beginHole = function () {
        this.finishPoly();
        this._holeMode = true;
        return this;
    };
    /**
     * 结束画洞
     */
    Graphics.prototype.endHole = function () {
        this.finishPoly();
        this._holeMode = false;
        return this;
    };
    /**
     * 画矩形
     * @param {number} x - 左上角x
     * @param {number} y - 左上角y
     * @param {number} width - 宽度
     * @param {number} height - 高度
     * @return {Graphics}
     */
    Graphics.prototype.drawRect = function (x, y, width, height) {
        return this.drawShape(new Rectangle(x, y, width, height));
    };
    /**
     * 画圆角矩形
     * @param {number} x - 左上角x
     * @param {number} y - 左上角y
     * @param {number} width - 宽度
     * @param {number} height - 高度
     * @param {number} radius - 圆角半径
     * @return {Graphics}
     */
    Graphics.prototype.drawRoundedRect = function (x, y, width, height, radius) {
        return this.drawShape(new RoundedRectangle(x, y, width, height, radius));
    };
    /**
     * 画圆形
     * @param {number} x - 圆中心x
     * @param {number} y - 圆中心y
     * @param {number} radius - 半径
     * @return {Graphics}
     */
    Graphics.prototype.drawCircle = function (x, y, radius) {
        return this.drawShape(new Circle(x, y, radius));
    };
    /**
     * 画椭圆
     * @param {number} x - 椭圆中心x
     * @param {number} y - 椭圆中心y
     * @param {number} width - 椭圆宽度一半，就是椭圆横向半径
     * @param {number} height - 椭圆高度一半，就是椭圆纵向半径
     * @return {Graphics}
     */
    Graphics.prototype.drawEllipse = function (x, y, width, height) {
        return this.drawShape(new Ellipse(x, y, width, height));
    };
    /**
     * 画多边形
     * @param {number[]|Point[]|Polygon} path - 多边形路径
     * @return {Graphics}
     */
    Graphics.prototype.drawPolygon = function (path) {
        // prevents an argument assignment deopt
        // see section 3.1: https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#3-managing-arguments
        var points = path;
        var closed = true;
        if (points instanceof Polygon) {
            closed = points.closed;
            points = points.points;
        }
        if (!Array.isArray(points)) {
            // prevents an argument leak deopt
            // see section 3.2: https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#3-managing-arguments
            points = new Array(arguments.length);
            for (var i = 0; i < points.length; ++i) {
                points[i] = arguments[i]; // eslint-disable-line prefer-rest-params
            }
        }
        var shape = new Polygon(points);
        shape.closed = closed;
        this.drawShape(shape);
        return this;
    };
    /**
     * 画任意多角形。points为数量
     * @param {number} x - 中心x
     * @param {number} y - 中心y
     * @param {number} points - 多角形数量。必须大于1
     * @param {number} radius - 多角形外半径
     * @param {number} [innerRadius] - 多角形内半径
     * @param {number} [rotation=0] - 角度，弧度制
     * @return {Graphics}
     */
    Graphics.prototype.drawStar = function (x, y, points, radius, innerRadius, rotation) {
        if (rotation === void 0) { rotation = 0; }
        innerRadius = innerRadius || radius / 2;
        var startAngle = (-1 * Math.PI / 2) + rotation;
        var len = points * 2;
        var delta = PI_2 / len;
        var polygon = [];
        for (var i = 0; i < len; i++) {
            var r = i % 2 ? innerRadius : radius;
            var angle = (i * delta) + startAngle;
            polygon.push(x + (r * Math.cos(angle)), y + (r * Math.sin(angle)));
        }
        return this.drawPolygon(polygon);
    };
    /**
     *
     * @param {Circle|Ellipse|Polygon|Rectangle|RoundedRectangle} shape
     * @return {Graphics}
     */
    Graphics.prototype.drawShape = function (shape) {
        if (!this._holeMode) {
            var data = new GraphicsData(shape, this._fillStyle.clone(), this._lineStyle.clone(), this._matrix);
            this.graphicsData.push(data);
            this.dirty++;
        }
        else {
            if (!this.graphicsData.length)
                return this;
            var data = new GraphicsData(shape, null, null, this._matrix);
            var lastShape = this.graphicsData[this.graphicsData.length - 1];
            lastShape.holes.push(data);
            this.dirty++;
        }
        return this;
    };
    /**
     * 清除绘图数据
     * @return {Graphics}
     */
    Graphics.prototype.clear = function () {
        if (this.graphicsData.length > 0) {
            this.boundsDirty = -1;
            this.dirty++;
            this.graphicsData.length = 0;
            this.verts.length = 0;
            this.uvs.length = 0;
            this.indices.length = 0;
            this.shapeIndex = 0;
            for (var i = 0; i < this.geoBatches.length; i++) {
                var batch = this.geoBatches[i];
                batch.start = 0;
                batch.attribStart = 0;
                batch.style = null;
                GEOBATCH_POOL.push(batch);
            }
            this.geoBatches.length = 0;
            //清空
            this.batches.length = 0;
        }
        this._currentPath = null;
        this._matrix = null;
        this._holeMode = false;
        this._currentPath = null;
        return this;
    };
    /**
     * 暂时不用
     * @returns {boolean}
     */
    Graphics.prototype.isFastRect = function () {
        // return this.graphicsData.length === 1
        //     && this.graphicsData[0].shape.type === SHAPES.RECT
        //     && !this.graphicsData[0].lineWidth;
        return false;
    };
    Graphics.prototype._renderWebGL = function (renderer) {
        //以防没有end，
        this.finishPoly();
        //更新批
        this.updateBatch();
        renderer.batchManager.setObjectRenderer(renderer.plugins["batch"]);
        //有才计算
        if (this.batches.length) {
            this.calculateVertices();
            this.calculateTints();
            for (var i = 0; i < this.batches.length; i++) {
                var batch = this.batches[i];
                //_worldAlpha可能会变
                batch._worldAlpha = this._worldAlpha * batch.graAlpha;
                renderer.plugins["batch"].render(batch);
            }
        }
    };
    /**
     * 根据GraphicsData分出batch，主要根据透明度和颜色
     * _texture  里面有.BaseTexture
     * _vertexData
     * _indices
     * graAlpha 图形透明度自身计算需要
     * _worldAlpha
     * _batchRGB  图形颜色自身计算需要
     * _tintRGB
     * _uvs
     */
    Graphics.prototype.updateBatch = function () {
        if (this.batchDirty === this.dirty)
            return;
        if (this.graphicsData.length === 0)
            return;
        this.batchDirty = this.dirty;
        var uvs = this.uvs;
        //取最后一个
        var batchPart;
        batchPart = this.geoBatches.pop();
        if (!batchPart) {
            batchPart = GEOBATCH_POOL.pop() || new geoBatchPart();
            batchPart.style = batchPart.style ||
                this.graphicsData[0].fillStyle ||
                this.graphicsData[0].lineStyle;
        }
        var currentTexture = batchPart.style.texture.baseTexture;
        var currentColor = batchPart.style.color + batchPart.style.alpha;
        this.geoBatches.push(batchPart);
        //先更新geoBatches
        //基本可能只有一个，多个时加
        for (var i = this.shapeIndex; i < this.graphicsData.length; i++) {
            this.shapeIndex++;
            var data = this.graphicsData[i];
            var command = fillCommands[data.type];
            var fillStyle = data.fillStyle;
            var lineStyle = data.lineStyle;
            //初始化 data里的points,fill和stroke一样的
            command.build(data);
            //有矩阵先转换点
            if (data.matrix)
                this.transformPoints(data.points, data.matrix);
            for (var j = 0; j < 2; j++) {
                var style = (j === 0) ? fillStyle : lineStyle;
                if (!style.visible)
                    continue;
                var nextTexture = style.texture.baseTexture;
                if (currentTexture !== nextTexture || (style.color + style.alpha) !== currentColor) {
                    nextTexture.wrapMode = WRAP_MODES.REPEAT;
                    currentTexture = nextTexture;
                    currentColor = style.color + style.alpha;
                    var index_1 = this.indices.length;
                    var attribIndex = this.verts.length / 2;
                    batchPart.size = index_1 - batchPart.start;
                    batchPart.attribSize = attribIndex - batchPart.attribStart;
                    if (batchPart.size > 0) {
                        batchPart = GEOBATCH_POOL.pop() || new geoBatchPart();
                        this.geoBatches.push(batchPart);
                    }
                    batchPart.style = style;
                    batchPart.start = index_1;
                    batchPart.attribStart = attribIndex;
                }
                var start = this.verts.length / 2;
                if (j === 0) {
                    //处理verts和indices
                    if (data.holes.length) {
                        this.proccessHoles(data.holes);
                        buildPoly.triangulate(data, this);
                    }
                    else {
                        command.triangulate(data, this);
                    }
                }
                else {
                    buildLine(data, this);
                }
                var size = (this.verts.length / 2) - start;
                this.addUvs(this.verts, uvs, style.texture, start, size, style.matrix);
            }
        }
        var index = this.indices.length;
        var attrib = this.verts.length / 2;
        batchPart.size = index - batchPart.start;
        batchPart.attribSize = attrib - batchPart.attribStart;
        var indicesUint16 = new Uint16Array(this.indices);
        var uvsFloat32 = new Float32Array(this.uvs);
        // offset the indices so that it works with the batcher...
        for (var i_1 = 0; i_1 < this.geoBatches.length; i_1++) {
            var batch = this.geoBatches[i_1];
            for (var j = 0; j < batch.size; j++) {
                var index_2 = batch.start + j;
                indicesUint16[index_2] = indicesUint16[index_2] - batch.attribStart;
            }
        }
        //设置_transformID，确保计算顶点数据
        this._transformID = -1;
        //确保颜色值要更新
        this.batchTint = -1;
        //更新batches
        this.batches = [];
        this.vertexData = new Float32Array(this.verts);
        var blendMode = this.blendMode;
        for (var i_2 = 0; i_2 < this.geoBatches.length; i_2++) {
            var gI = this.geoBatches[i_2];
            var color = gI.style.color;
            var vertexData = new Float32Array(this.vertexData.buffer, gI.attribStart * 4 * 2, gI.attribSize * 2);
            var uvs_1 = new Float32Array(uvsFloat32.buffer, gI.attribStart * 4 * 2, gI.attribSize * 2);
            var indices = new Uint16Array(indicesUint16.buffer, gI.start * 2, gI.size);
            var batch = {
                _vertexData: vertexData,
                _indices: indices,
                _uvs: uvs_1,
                _tintRGB: color,
                _texture: gI.style.texture,
                _worldAlpha: 1,
                _blendMode: blendMode,
                graAlpha: gI.style.alpha,
                _batchRGB: hex2rgb$1(color),
            };
            this.batches[i_2] = batch;
        }
    };
    /**
     * 对每个batch计算颜色
     * @protected
     */
    Graphics.prototype.calculateTints = function () {
        if (this.batchTint !== this.tint) {
            this.batchTint = this.tint;
            var tintRGB = hex2rgb$1(this.tint, temp);
            for (var i = 0; i < this.batches.length; i++) {
                var batch = this.batches[i];
                var batchTint = batch._batchRGB;
                var r = (tintRGB[0] * batchTint[0]) * 255;
                var g = (tintRGB[1] * batchTint[1]) * 255;
                var b = (tintRGB[2] * batchTint[2]) * 255;
                // TODO Ivan, can this be done in one go?
                var color = (r << 16) + (g << 8) + (b | 0);
                batch._tintRGB = (color >> 16)
                    + (color & 0xff00)
                    + ((color & 0xff) << 16);
            }
        }
    };
    /**
     * 计算顶点
     * @protected
     */
    Graphics.prototype.calculateVertices = function () {
        if (this._transformID === this.transform._worldID) {
            return;
        }
        this._transformID = this.transform._worldID;
        var wt = this.transform.worldMatrix;
        var a = wt.a;
        var b = wt.b;
        var c = wt.c;
        var d = wt.d;
        var tx = wt.tx;
        var ty = wt.ty;
        var data = this.verts; // batch.vertexDataOriginal;
        var vertexData = this.vertexData;
        var count = 0;
        for (var i = 0; i < data.length; i += 2) {
            var x = data[i];
            var y = data[i + 1];
            vertexData[count++] = (a * x) + (c * y) + tx;
            vertexData[count++] = (d * y) + (b * x) + ty;
        }
    };
    Graphics.prototype.transformPoints = function (points, matrix) {
        for (var i = 0; i < points.length / 2; i++) {
            var x = points[(i * 2)];
            var y = points[(i * 2) + 1];
            points[(i * 2)] = (matrix.a * x) + (matrix.c * y) + matrix.tx;
            points[(i * 2) + 1] = (matrix.b * x) + (matrix.d * y) + matrix.ty;
        }
    };
    /**
     * canvas渲染
     * @private
     * @param {CanvasRenderer} renderer - The renderer
     */
    Graphics.prototype._renderCanvas = function (renderer) {
        //以防没有end，
        this.finishPoly();
        if (this.cacheAsBitmap) {
            if (this.cacheDirty != this.dirty) {
                this.cacheDirty = this.dirty;
                //如果在生成贴图时需要去掉遮罩和缓存属性
                var tempMask = this.mask;
                this.mask = null;
                this.cacheAsBitmap = false;
                var tempAlpha = this.alpha;
                this.alpha = 1;
                var tempChildren = this.children; //待测试，预存子级
                this.children = []; //置空子级，防止离屏canvas绘制
                this.generateCanvasTexture();
                //恢复
                this.mask = tempMask;
                this.alpha = tempAlpha;
                this.cacheAsBitmap = true;
                this.children = tempChildren; //待测试，还原原先子级
                // if (this.parent) {
                //generateCanvasTexture里用canvasRenderer渲染会修改世界矩阵，保证自己能根据父级矩阵更新回来
                this.transform._parentID = -1;
                if (this.parent)
                    this.updateTransform(); //有父级，直接执行一次先，待测试
                // }
            }
            //普通画图的渲染，提供图片和图形的插件，先判断_anchorTexture，offsetX,0
            renderer.plugins.sprite.render(this);
        }
        else {
            renderer.plugins.graphics.render(this);
        }
    };
    /**
     * _boundsId不知道怎么改，暂时不管，少用
     * 计算全局bounds，_localBoundsSelf做个全局转换就行
     * @private
     */
    Graphics.prototype._calculateBounds = function () {
        this.updateLocalBoundsSelf();
        var rect = this._localBoundsSelf;
        var matrix = this.transform.worldMatrix;
        matrix.transformPoint(rect.x, rect.y, DisplayObject._p1);
        matrix.transformPoint(rect.x + rect.width, rect.y, DisplayObject._p2);
        matrix.transformPoint(rect.x + rect.width, rect.y + rect.height, DisplayObject._p3);
        matrix.transformPoint(rect.x, rect.y + rect.height, DisplayObject._p4);
        Rectangle.createFromPoints(this._bounds, DisplayObject._p1, DisplayObject._p2, DisplayObject._p3, DisplayObject._p4);
    };
    /**
     * 碰撞检测方法重写
     * @param {Point} point - 全局坐标点
     */
    Graphics.prototype.hitTestPoint = function (point, isMouseEvent) {
        if (isMouseEvent === void 0) { isMouseEvent = false; }
        //不可见，直接返回
        if (!this.visible)
            return null;
        var hitDisplayObject;
        //先检查子级，因为子级层级更高
        hitDisplayObject = _super.prototype.hitTestPoint.call(this, point, isMouseEvent);
        //子级已有，返回
        if (hitDisplayObject)
            return hitDisplayObject;
        //子级没有的话，为了可以不updateLocalBoundsSelf，判断一下
        if (isMouseEvent && !this.mouseEnable)
            return null;
        //再粗略检查自己，先计算自身盒子
        this.updateLocalBoundsSelf();
        hitDisplayObject = this.displayObjectHitTestPoint(point, isMouseEvent);
        //如果
        if (hitDisplayObject) {
            //不需要像素级检测直接返回
            if (!this.hitTestByPixel)
                return hitDisplayObject;
            //精确检测
            return this.hitTestPointAccuratly(point, isMouseEvent);
        }
        return null;
    };
    /**
     * 精确检测
     * 用几何方法
     * 不像shape里用的像素值
     * @param point
     */
    Graphics.prototype.hitTestPointAccuratly = function (point, isMouseEvent) {
        var s = this;
        if (isMouseEvent) {
            this.worldMatrix.transformPointInverse(point.x, point.y, tempPoint$2);
        }
        else {
            tempPoint$2.set(point.x, point.y);
        }
        var graphicsData = this.graphicsData;
        for (var i = 0; i < graphicsData.length; ++i) {
            var data = graphicsData[i];
            //只管填充的，不可见就跳过
            if (!data.fillStyle.visible && !data.fillStyle.alphaBlock)
                continue;
            //没有shape的跳过
            if (!data.shape)
                continue;
            //没在shape内的跳过
            if (!data.shape.isPointIn(tempPoint$2))
                continue;
            //没有洞直接返回自身
            if (!data.holes || !data.holes.length)
                return s;
            //判断洞
            var inHole = false;
            for (var i_3 = 0; i_3 < data.holes.length; i_3++) {
                var hole = data.holes[i_3].shape;
                //在任何一个洞内，就跳出循环
                if (hole.isPointIn(tempPoint$2)) {
                    inHole = true;
                    break;
                }
            }
            //不在洞里可以直接返回自身了
            if (!inHole)
                return s;
        }
        return null;
    };
    /**
     * 更新自身包围盒
     */
    Graphics.prototype.updateLocalBoundsSelf = function () {
        if (this.boundsDirty == this.dirty)
            return;
        this.boundsDirty = this.dirty;
        //以防止调用的时候没有end
        this.finishPoly();
        var minX = Infinity;
        var maxX = -Infinity;
        var minY = Infinity;
        var maxY = -Infinity;
        if (this.graphicsData.length) {
            var shape = void 0;
            var x = 0;
            var y = 0;
            var w = 0;
            var h = 0;
            for (var i = 0; i < this.graphicsData.length; i++) {
                var data = this.graphicsData[i];
                var type = data.type;
                var lineStyle = data.lineStyle;
                //矩阵的应该暂时没写，暂时不用
                data.matrix || Matrix.IDENTITY;
                var lineWidth = 0.0;
                if (lineStyle && lineStyle.visible) {
                    var alignment = lineStyle.alignment;
                    lineWidth = lineStyle.width;
                    if (type === SHAPES.POLY) ;
                    else {
                        lineWidth = lineWidth * Math.max(0, alignment);
                    }
                }
                shape = data.shape;
                if (type === SHAPES.RECT || type === SHAPES.RREC) {
                    x = shape.x - lineWidth;
                    y = shape.y - lineWidth;
                    w = shape.width + lineWidth * 2;
                    h = shape.height + lineWidth * 2;
                    minX = x < minX ? x : minX;
                    maxX = x + w > maxX ? x + w : maxX;
                    minY = y < minY ? y : minY;
                    maxY = y + h > maxY ? y + h : maxY;
                }
                else if (type === SHAPES.CIRC) {
                    x = shape.x;
                    y = shape.y;
                    w = shape.radius + lineWidth;
                    h = shape.radius + lineWidth;
                    minX = x - w < minX ? x - w : minX;
                    maxX = x + w > maxX ? x + w : maxX;
                    minY = y - h < minY ? y - h : minY;
                    maxY = y + h > maxY ? y + h : maxY;
                }
                else if (type === SHAPES.ELIP) {
                    x = shape.x;
                    y = shape.y;
                    w = shape.width + lineWidth;
                    h = shape.height + lineWidth;
                    minX = x - w < minX ? x - w : minX;
                    maxX = x + w > maxX ? x + w : maxX;
                    minY = y - h < minY ? y - h : minY;
                    maxY = y + h > maxY ? y + h : maxY;
                }
                else {
                    // POLY
                    var poly = shape;
                    var points = poly.points;
                    var x2 = 0;
                    var y2 = 0;
                    var dx = 0;
                    var dy = 0;
                    var rw = 0;
                    var rh = 0;
                    var cx = 0;
                    var cy = 0;
                    for (var j = 0; j + 2 < points.length; j += 2) {
                        x = points[j];
                        y = points[j + 1];
                        x2 = points[j + 2];
                        y2 = points[j + 3];
                        dx = Math.abs(x2 - x);
                        dy = Math.abs(y2 - y);
                        h = lineWidth;
                        w = Math.sqrt((dx * dx) + (dy * dy));
                        if (w < 1e-9) {
                            continue;
                        }
                        rw = ((h / w * dy) + dx) / 2;
                        rh = ((h / w * dx) + dy) / 2;
                        cx = (x2 + x) / 2;
                        cy = (y2 + y) / 2;
                        //有线宽，且不居中的时候，中心点需要做偏移，下面和上面有很多重复计算
                        if (lineWidth && lineStyle.alignment != LINE_ALIGNMENT.middle) {
                            var width = lineWidth / 2;
                            var perpx = -(y - y2);
                            var perpy = x - x2;
                            perpx /= w;
                            perpy /= w;
                            perpx *= width;
                            perpy *= width;
                            var ratio = lineStyle.alignment;
                            var innerWeight = (1 - ratio);
                            var outerWeight = ratio;
                            if (ratio == LINE_ALIGNMENT.inner) {
                                cx -= perpx * innerWeight;
                                cy -= perpy * innerWeight;
                            }
                            else {
                                cx += perpx * outerWeight;
                                cy += perpy * outerWeight;
                            }
                        }
                        minX = cx - rw < minX ? cx - rw : minX;
                        maxX = cx + rw > maxX ? cx + rw : maxX;
                        minY = cy - rh < minY ? cy - rh : minY;
                        maxY = cy + rh > maxY ? cy + rh : maxY;
                        //如果没有闭合，需要判断末端顶点（round和square都需要额外加点动），以后再说了TODO，不好搞，现在随便搞下先
                        if (lineWidth && !poly.closed) {
                            //第一个点
                            if (j == 0) { //这种方式根本就不需要上面那样的计算
                                minX = Math.min(minX, x - lineWidth);
                                maxX = Math.max(maxX, x + lineWidth);
                                minY = Math.min(minY, y - lineWidth);
                                maxY = Math.max(maxY, y + lineWidth);
                            }
                            //最后一个点
                            if (j + 4 == points.length) {
                                minX = Math.min(minX, x2 - lineWidth);
                                maxX = Math.max(maxX, x2 + lineWidth);
                                minY = Math.min(minY, y2 - lineWidth);
                                maxY = Math.max(maxY, y2 + lineWidth);
                            }
                        }
                        //还需要判断连接点，，，咋搞TODO
                        if (lineWidth && j + 4 !== points.length) ;
                    }
                }
            }
        }
        else {
            minX = 0;
            maxX = 0;
            minY = 0;
            maxY = 0;
        }
        var padding = this.boundsPadding;
        this._localBoundsSelf.x = minX - padding;
        this._localBoundsSelf.y = minY - padding;
        this._localBoundsSelf.width = maxX - minX + padding * 2;
        this._localBoundsSelf.height = maxY - minY + padding * 2;
    };
    /**
     * 生成离屏canvas纹理
     * 不包括变形的，只根据图形数据产生的原生贴图，经过变形的，考虑，是否新建方法，这个暂时只为canvas缓存
     * 也不考虑遮罩
     * @param {SCALE_MODES} scaleMode 纹理缩放模式
     * @return {Texture} 离屏纹理
     */
    Graphics.prototype.generateCanvasTexture = function (scaleMode) {
        if (scaleMode === void 0) { scaleMode = SCALE_MODES.LINEAR; }
        this.updateLocalBoundsSelf();
        var bounds = this._localBoundsSelf;
        if (!this._canvasBuffer) {
            this._canvasBuffer = RenderTexture.create(bounds.width, bounds.height, scaleMode);
        }
        else {
            this._canvasBuffer.resize(bounds.width, bounds.height);
        }
        if (!canvasRenderer) {
            canvasRenderer = new CanvasRenderer(null, 0, 0);
        }
        this.transform.updateLocalMatrix();
        tempMatrix$3.copy(this.transform.localMatrix);
        tempMatrix$3.invert();
        tempMatrix$3.tx -= bounds.x;
        tempMatrix$3.ty -= bounds.y;
        canvasRenderer.render(this, this._canvasBuffer, tempMatrix$3);
        // document.body.appendChild(this._canvasBuffer.baseTexture["_canvasRenderTarget"].canvas)
        if (!this._texture) {
            this._texture = Texture.fromCanvas(this._canvasBuffer.baseTexture["_canvasRenderTarget"].canvas, 'graphics');
            this._texture.baseTexture.update();
        }
        else {
            this._texture.baseTexture.update();
        }
        //可能需要更改_texture，this._texture.baseTexture尺寸
        // this.offsetX = bounds.x;
        // this.offsetY = bounds.y;
        return this._texture;
        // return
    };
    /**
     * 销毁
     */
    Graphics.prototype.destroy = function () {
        _super.prototype.destroy.call(this);
        // destroy each of the GraphicsData objects
        for (var i = 0; i < this.graphicsData.length; ++i) {
            this.graphicsData[i].destroy();
        }
        this._matrix = null;
        this._currentPath = null;
        this._lineStyle.destroy();
        this._lineStyle = null;
        this._fillStyle.destroy();
        this._fillStyle = null;
        this.vertexData = null;
        this.geoBatches.length = 0;
        this.geoBatches = null;
        this.batches.length = 0;
        this.batches = null;
    };
    Object.defineProperty(Graphics.prototype, "width", {
        /**
         * 设置会影响缩放
         */
        get: function () {
            this.updateLocalBoundsSelf();
            return Math.abs(this.scale.x) * this._localBoundsSelf.width;
        },
        set: function (value) {
            this.updateLocalBoundsSelf();
            var width = this._localBoundsSelf.width;
            if (width !== 0) {
                var s = sign(this.scale.x) || 1;
                this.scale.x = s * value / width;
            }
            else {
                this.scale.x = 1;
            }
            this._width = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Graphics.prototype, "height", {
        /**
         * 设置会影响缩放
         */
        get: function () {
            this.updateLocalBoundsSelf();
            return Math.abs(this.scale.y) * this._localBoundsSelf.height;
        },
        set: function (value) {
            this.updateLocalBoundsSelf();
            var height = this._localBoundsSelf.height;
            if (height !== 0) {
                var s = sign(this.scale.y) || 1;
                this.scale.y = s * value / height;
            }
            else {
                this.scale.y = 1;
            }
            this._height = value;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 处理洞数据
     * @param {GraphicsData[]} holes
     * @protected
     */
    Graphics.prototype.proccessHoles = function (holes) {
        for (var i = 0; i < holes.length; i++) {
            var hole = holes[i];
            var command = fillCommands[hole.type];
            command.build(hole);
            if (hole.matrix)
                this.transformPoints(hole.points, hole.matrix);
        }
    };
    /**
     * 生成uv
     * 不支持纹理填充，所以uv都时0
     * @protected
     * @param {number[]} verts - 顶点
     * @param {number[]} uvs - UVs
     * @param {Texture} texture - 纹理
     * @param {number} start - 索引开始点
     * @param {number} size - 索引长度
     * @param {Matrix} [matrix] - 所有点的偏移矩阵
     */
    Graphics.prototype.addUvs = function (verts, uvs, texture, start, size, matrix) {
        var index = 0;
        var uvsStart = uvs.length;
        var frame = texture.frame;
        while (index < size) {
            var x = verts[(start + index) * 2];
            var y = verts[((start + index) * 2) + 1];
            //矩阵应用还有问题
            if (matrix) {
                var nx = (matrix.a * x) + (matrix.c * y) + matrix.tx;
                y = (matrix.b * x) + (matrix.d * y) + matrix.ty;
                x = nx;
            }
            index++;
            var frame_1 = texture.frame;
            uvs.push(x / frame_1.width, y / frame_1.height);
            //uvs.push(0, 0);
        }
        var baseTexture = texture.baseTexture;
        if (frame.width < baseTexture.width
            || frame.height < baseTexture.height) {
            this.adjustUvs(uvs, texture, uvsStart, size);
        }
    };
    /**
     * 修正由纹理区域位置引起的uv
     * 对于旋转的或透明度裁切的纹理无效
     * @param {number[]} uvs
     * @param {Texture} texture
     * @param {number} start
     * @param {number} size
     */
    Graphics.prototype.adjustUvs = function (uvs, texture, start, size) {
        var baseTexture = texture.baseTexture;
        var eps = 1e-6;
        var finish = start + (size * 2);
        var frame = texture.frame;
        var scaleX = frame.width / baseTexture.width;
        var scaleY = frame.height / baseTexture.height;
        var offsetX = frame.x / frame.width;
        var offsetY = frame.y / frame.height;
        var minX = Math.floor(uvs[start] + eps);
        var minY = Math.floor(uvs[start + 1] + eps);
        for (var i = start + 2; i < finish; i += 2) {
            minX = Math.min(minX, Math.floor(uvs[i] + eps));
            minY = Math.min(minY, Math.floor(uvs[i + 1] + eps));
        }
        offsetX -= minX;
        offsetY -= minY;
        for (var i = start; i < finish; i += 2) {
            uvs[i] = (uvs[i] + offsetX) * scaleX;
            uvs[i + 1] = (uvs[i + 1] + offsetY) * scaleY;
        }
    };
    return Graphics;
}(Container));
/**
 * 为了批处理建的临时类
 */
var geoBatchPart = /** @class */ (function () {
    function geoBatchPart() {
        this.style = null;
        this.size = 0;
        this.start = 0;
        this.attribStart = 0;
        this.attribSize = 0;
    }
    return geoBatchPart;
}());

/**
 * 继承sprite，hittest重写
 * 矢量对象，
 * 记录指令，对于复杂的不常绘制的图形，用canvas上下文的指令比较方便，比如消消乐项目时的格子地图
 * 复杂路径，自己没法确定哪些区域该填充的时候，用canvas的api
 * 支持pattern和渐变填充，与Graphic的纹理填充区分，不一致
 * anchorTexture被使用，尽量不手动修改，如要改锚点，用anchor
 * 作为Webgl模式的遮罩时，需要注意：
 * 遮罩绘制指令不变的且有矩阵变化的（比如自身或父级的位置有改变），需要shape._boundsID++，为了重新计算包围盒
 * @class Shape
 * @extends Sprite
 */
var Shape = /** @class */ (function (_super) {
    __extends(Shape, _super);
    // offsetX: number;
    // offsetY: number;
    function Shape() {
        var _this = _super.call(this) || this;
        /**
         * 一个数组，每个元素也是一个数组[类型 0是属性,1是方法,名字 执行的属性或方法名,参数]
         *
         * @property _command
         * @private
         * @since 1.0.0
         * @type {Array}
         * @default []
         */
        _this._command = [];
        /**
         * 是否对矢量使用像素碰撞 默认开启
         * @property hitTestByPixel
         * @type {boolean}
         * @default true
         * @since 1.1.0
         */
        _this.hitTestByPixel = true;
        /**
         * 标记是否作为遮罩，作为遮罩时不会被当作hittest检测对象，默认false，内部逻辑处理用，外部不建议修改
         */
        _this._isUsedToMask = false;
        _this._instanceType = "Shape";
        var canvas = createCanvas();
        canvas.width = 3;
        canvas.height = 3;
        _this.texture = Texture.fromCanvas(canvas, 'shapeCanvas');
        //baseTexture已自动缓存，把texture也缓存，key textCanvas+num  和baseTexture的一致
        Texture.addToCache(_this.texture, _this.texture.baseTexture.textureCacheIds[0]);
        _this.canvas = canvas;
        _this.context = canvas.getContext("2d");
        _this.dirty = true;
        return _this;
    }
    /**
     * 画一个带圆角的矩形
     * @method drawRoundedRect
     * @param {number} x 点x值
     * @param {number} y 点y值
     * @param {number} w 宽
     * @param {number} h 高
     * @param {number} rTL 左上圆角半径
     * @param {number} rTR 右上圆角半径
     * @param {number} rBL 左下圆角半径
     * @param {number} rBR 右上圆角半径
     * @public
     * @since 1.0.0
     */
    Shape.prototype.drawRoundedRect = function (x, y, w, h, rTL, rTR, rBL, rBR) {
        if (rTL === void 0) { rTL = 0; }
        var max = (w < h ? w : h) / 2;
        var mTL = 0, mTR = 0, mBR = 0, mBL = 0;
        if (rTR == undefined)
            rTR = rTL;
        if (rBL == undefined)
            rBL = rTL;
        if (rBR == undefined)
            rBR = rTL;
        if (rTL < 0) {
            rTL *= (mTL = -1);
        }
        if (rTL > max) {
            rTL = max;
        }
        if (rTR < 0) {
            rTR *= (mTR = -1);
        }
        if (rTR > max) {
            rTR = max;
        }
        if (rBR < 0) {
            rBR *= (mBR = -1);
        }
        if (rBR > max) {
            rBR = max;
        }
        if (rBL < 0) {
            rBL *= (mBL = -1);
        }
        if (rBL > max) {
            rBL = max;
        }
        var c = this._command;
        c[c.length] = [1, "moveTo", [x + w - rTR, y]];
        c[c.length] = [1, "arcTo", [x + w + rTR * mTR, y - rTR * mTR, x + w, y + rTR, rTR]];
        c[c.length] = [1, "lineTo", [x + w, y + h - rBR]];
        c[c.length] = [1, "arcTo", [x + w + rBR * mBR, y + h + rBR * mBR, x + w - rBR, y + h, rBR]];
        c[c.length] = [1, "lineTo", [x + rBL, y + h]];
        c[c.length] = [1, "arcTo", [x - rBL * mBL, y + h + rBL * mBL, x, y + h - rBL, rBL]];
        c[c.length] = [1, "lineTo", [x, y + rTL]];
        c[c.length] = [1, "arcTo", [x - rTL * mTL, y - rTL * mTL, x + rTL, y, rTL]];
        c[c.length] = [1, "closePath", []];
        return this;
    };
    /**
     * 绘画时移动到某一点
     * @method moveTo
     * @param {number} x
     * @param {number} y
     * @public
     * @since 1.0.0
     */
    Shape.prototype.moveTo = function (x, y) {
        this._command[this._command.length] = [1, "moveTo", [x, y]];
        return this;
    };
    /**
     * 从上一点画到某一点,如果没有设置上一点，则上一点默认为(0,0)
     * @method lineTo
     * @param {number} x
     * @param {number} y
     * @public
     * @since 1.0.0
     */
    Shape.prototype.lineTo = function (x, y) {
        this._command[this._command.length] = [1, "lineTo", [x, y]];
        return this;
    };
    /**
     *
     * https://www.jianshu.com/p/e8ea5996cd79
     * @method arcTo
     * @param {number} x1 圆弧外一点，由它连接两切点
     * @param {number} y1
     * @param {number} x2 结束点 没啥用，设啥都是那个切点
     * @param {number} y2
     * @param {number} radius 半径
     * @public
     * @since 1.0.0
     */
    Shape.prototype.arcTo = function (x1, y1, x2, y2, radius) {
        this._command[this._command.length] = [1, "arcTo", [x1, y1, x2, y2, radius]];
        return this;
    };
    /**
     * 二次贝赛尔曲线
     * 从上一点画二次贝赛尔曲线到某一点,如果没有设置上一点，则上一占默认为(0,0)
     * @method quadraticCurveTo
     * @param {number} cpX 控制点X
     * @param {number} cpX 控制点Y
     * @param {number} x 终点X
     * @param {number} y 终点Y
     * @public
     * @since 1.0.0
     */
    Shape.prototype.quadraticCurveTo = function (cpX, cpY, x, y) {
        this._command[this._command.length] = [1, "quadraticCurveTo", [cpX, cpY, x, y]];
        return this;
    };
    /**
     * 三次贝赛尔曲线
     * 从上一点画二次贝赛尔曲线到某一点,如果没有设置上一点，则上一点默认为(0,0)
     * @method bezierCurveTo
     * @param {number} cp1X 1控制点X
     * @param {number} cp1Y 1控制点Y
     * @param {number} cp2X 2控制点X
     * @param {number} cp2Y 2控制点Y
     * @param {number} x 终点X
     * @param {number} y 终点Y
     * @public
     * @since 1.0.0
     */
    Shape.prototype.bezierCurveTo = function (cp1X, cp1Y, cp2X, cp2Y, x, y) {
        this._command[this._command.length] = [1, "bezierCurveTo", [cp1X, cp1Y, cp2X, cp2Y, x, y]];
        return this;
    };
    /**
     * 闭合一个绘画路径
     * @method closePath
     * @public
     * @since 1.0.0
     */
    Shape.prototype.closePath = function () {
        this._command[this._command.length] = [1, "closePath", []];
        return this;
    };
    /**
     * 画一个矩形
     * @method drawRect
     * @param {number} x
     * @param {number} y
     * @param {number} w
     * @param {number} h
     * @public
     * @since 1.0.0
     */
    Shape.prototype.drawRect = function (x, y, w, h) {
        var c = this._command;
        c[c.length] = [1, "moveTo", [x, y]];
        c[c.length] = [1, "lineTo", [x + w, y]];
        c[c.length] = [1, "lineTo", [x + w, y + h]];
        c[c.length] = [1, "lineTo", [x, y + h]];
        c[c.length] = [1, "closePath", []];
        return this;
    };
    /**
     * 画一个弧形
     * https://www.w3school.com.cn/tags/canvas_arc.asp
     *
     * @method drawArc
     * @param {number} x 起始点x
     * @param {number} y 起始点y
     * @param {number} radius 半径
     * @param {number} start 开始角度 弧度
     * @param {number} end 结束角度 弧度
     * @param {number} counterclockwise False = 顺时针，true = 逆时针
     * @public
     * @since 1.0.0
     */
    Shape.prototype.arc = function (x, y, radius, startAngle, endAngle, counterclockwise) {
        if (counterclockwise === void 0) { counterclockwise = false; }
        this._command[this._command.length] = [1, "arc", [x, y, radius, startAngle, endAngle, counterclockwise]];
        return this;
    };
    /**
     * 画一个圆
     * @method drawCircle
     * @param {number} x 圆心x
     * @param {number} y 圆心y
     * @param {number} radius 半径
     * @param {boolean} counterclockwise 方向，默认false，即顺时针
     * @public
     * @since 1.0.0
     */
    Shape.prototype.drawCircle = function (x, y, radius, counterclockwise) {
        if (counterclockwise === void 0) { counterclockwise = false; }
        this._command[this._command.length] = [1, "arc", [x, y, radius, 0, 2 * Math.PI, counterclockwise]];
        return this;
    };
    /**
     * 画一个椭圆
     * @method drawEllipse
     * @param {number} x 椭圆中心点x
     * @param {number} y 椭圆中心点y
     * @param {number} radiusX 横向半径
     * @param {number} radiusY 垂直半径
     * @public
     * @since 1.0.0
     */
    Shape.prototype.drawEllipse = function (x, y, radiusX, radiusY) {
        //先不加，否则下面command解析需要改下，没有该参数长度8，传参也需要设计下
        // if(this.context.ellipse){
        //     this._command[this._command.length] = [1, "ellipse", [x, y, w/2, h/2,0,0, 2 * Math.PI, false]];
        // }
        var k = 0.5522848;
        var ox = radiusX * k; // 水平控制点偏移量
        var oy = radiusY * k; // 垂直控制点偏移量
        var c = this._command;
        //从椭圆的左端点开始顺时针绘制四条三次贝塞尔曲线
        c[c.length] = [1, "moveTo", [x - radiusX, y]];
        c[c.length] = [1, "bezierCurveTo", [x - radiusX, y - oy, x - ox, y - radiusY, x, y - radiusY]];
        c[c.length] = [1, "bezierCurveTo", [x + ox, y - radiusY, x + radiusX, y - oy, x + radiusX, y]];
        c[c.length] = [1, "bezierCurveTo", [x + radiusX, y + oy, x + ox, y + radiusY, x, y + radiusY]];
        c[c.length] = [1, "bezierCurveTo", [x - ox, y + radiusY, x - radiusX, y + oy, x - radiusX, y]];
        return this;
    };
    /**
     * 清除掉之前所有绘画的东西
     * @method clear
     * @public
     * @since 1.0.0
     */
    Shape.prototype.clear = function () {
        var s = this;
        s._command = [];
        s.dirty = true;
        return s;
    };
    /**
     * 开始绘画填充,如果想画的东西有颜色填充,一定要从此方法开始
     * @method beginFill
     * @param {number|string} color 颜色值 十六进制颜色0xff0000，"#ff0000"
     * @public
     * @since 1.0.0
     */
    Shape.prototype.beginFill = function (color, alpha) {
        if (color === void 0) { color = 0; }
        if (alpha === void 0) { alpha = 1; }
        //数字形式转字符串
        if (typeof (color) == "number")
            color = hex2string(color);
        var sColor = getRGBA(color, alpha);
        this._fill(sColor);
        return this;
    };
    /**
     * 线性或径向渐变填充
     * @method beginGradientFill
     * @param {Array} points 四个数字表示线性渐变参考createLinearGradient，六个数字表示径向渐变参考createRadialGradient
     * @param {Array} colors [系数, #式颜色值, 透明度]的数组，比如[[0, "#ff0000", 1],[0.5, "#00ff00", 1],[1, "#0000ff", 1]]
     * @public
     * @since 1.0.0
     */
    Shape.prototype.beginGradientFill = function (points, colors) {
        this._fill(getGradientColor(points, colors));
        return this;
    };
    /**
     * 位图填充
     * @method beginBitmapFill
     * @param {Image} image
     * @param { Array} matrix
     * @public
     * @since 1.0.0
     */
    Shape.prototype.beginBitmapFill = function (image, matrix) {
        var s = this;
        if (matrix) {
            s._isBitmapFill = matrix;
        }
        s._fill(getCanvasBitmapStyle(image));
        return s;
    };
    Shape.prototype._fill = function (fillStyle) {
        var c = this._command;
        c[c.length] = [0, "fillStyle", fillStyle];
        c[c.length] = [1, "beginPath", []];
        this.dirty = true;
    };
    /**
     * 给线条着色
     * @method beginStroke
     * @param {number|string} color  颜色值,十六进制颜色0xff0000，"#ff0000"
     * @param {number} lineWidth 宽度
     * @param {number} cap 线头的形状 0 butt 1 round 2 square 默认 butt
     * @param {number} join 线与线之间的交接处形状 0 miter 1 bevel 2 round  默认miter
     * @param {number} miter 正数,规定最大斜接长度,如果斜接长度超过 miterLimit 的值，边角会以 lineJoin 的 "bevel" 类型来显示 默认10
     * @public
     * @since 1.0.0
     */
    Shape.prototype.beginStroke = function (color, lineWidth, cap, join, miter, alpha) {
        if (color === void 0) { color = 0; }
        if (lineWidth === void 0) { lineWidth = 1; }
        if (cap === void 0) { cap = LINE_CAP.BUTT; }
        if (join === void 0) { join = LINE_JOIN.MITER; }
        if (miter === void 0) { miter = 10; }
        if (alpha === void 0) { alpha = 1; }
        if (typeof (color) == "number")
            color = hex2string(color);
        var sColor = getRGBA(color, alpha);
        this._stroke(sColor, lineWidth, cap, join, miter);
        return this;
    };
    /**
     * 画线性或径向渐变的线条
     * @method beginGradientStroke
     * @param {Array} points 四个数字表示线性渐变参考createLinearGradient，六个数字表示径向渐变参考createRadialGradient
     * @param {Array} colors [系数, #式颜色值, 透明度]的数组，比如[[0, "#ff0000", 1],[0.5, "#00ff00", 1],[1, "#0000ff", 1]]
     * @param {number} lineWidth
     * @param {number} cap 线头的形状 0 butt 1 round 2 square 默认 butt
     * @param {number} join 线与线之间的交接处形状 0 miter 1 bevel 2 round  默认miter
     * @param {number} miter 正数,规定最大斜接长度,如果斜接长度超过 miterLimit 的值，边角会以 lineJoin 的 "bevel" 类型来显示 默认10
     * @public
     * @since 1.0.0
     */
    Shape.prototype.beginGradientStroke = function (points, colors, lineWidth, cap, join, miter) {
        if (lineWidth === void 0) { lineWidth = 1; }
        if (cap === void 0) { cap = LINE_CAP.BUTT; }
        if (join === void 0) { join = LINE_JOIN.MITER; }
        if (miter === void 0) { miter = 10; }
        this._stroke(getGradientColor(points, colors), lineWidth, cap, join, miter);
        return this;
    };
    /**
     * 线条位图填充
     * @method beginBitmapStroke
     * @param {Image} image
     * @param {Array} matrix
     * @param {number} lineWidth
     * @param {string} cap 线头的形状 butt round square 默认 butt
     * @param {string} join 线与线之间的交接处形状 bevel round miter 默认miter
     * @param {number} miter 正数,规定最大斜接长度,如果斜接长度超过 miterLimit 的值，边角会以 lineJoin 的 "bevel" 类型来显示 默认10
     * @public
     * @since 1.0.0
     */
    Shape.prototype.beginBitmapStroke = function (image, matrix, lineWidth, cap, join, miter) {
        if (lineWidth === void 0) { lineWidth = 1; }
        if (cap === void 0) { cap = LINE_CAP.BUTT; }
        if (join === void 0) { join = LINE_JOIN.MITER; }
        if (miter === void 0) { miter = 10; }
        var s = this;
        if (matrix) {
            s._isBitmapStroke = matrix;
        }
        s._stroke(getCanvasBitmapStyle(image), lineWidth, cap, join, miter);
        return s;
    };
    /**
     * @method _stroke
     * @param strokeStyle
     * @param {number} width
     * @param {number} cap
     * @param {number} join
     * @param {number} miter
     * @private
     * @since 1.0.0
     */
    Shape.prototype._stroke = function (strokeStyle, width, cap, join, miter) {
        var c = this._command;
        c[c.length] = [0, "lineWidth", width];
        c[c.length] = [0, "lineCap", cap];
        c[c.length] = [0, "lineJoin", join];
        c[c.length] = [0, "miterLimit", miter];
        c[c.length] = [0, "strokeStyle", strokeStyle];
        c[c.length] = [1, "beginPath", []];
        this.dirty = true;
    };
    /**
     * 结束填充
     * @method endFill
     * @public
     * @since 1.0.0
     */
    Shape.prototype.endFill = function () {
        var s = this;
        var c = s._command;
        var m = s._isBitmapFill;
        if (m) {
            c[c.length] = [2, "setTransform", m];
        }
        c[c.length] = ([1, "fill", []]);
        if (m) {
            s._isBitmapFill = null;
        }
        return s;
    };
    /**
     * 结束画线
     * @method endStroke
     * @public
     * @since 1.0.0
     */
    Shape.prototype.endStroke = function () {
        var s = this;
        var c = s._command;
        var m = s._isBitmapStroke;
        if (m) {
            //如果为2则还需要特别处理
            c[c.length] = [2, "setTransform", m];
        }
        c[c.length] = ([1, "stroke", []]);
        if (m) {
            s._isBitmapStroke = null;
        }
        return s;
    };
    /**
     * 重写刷新
     * @method update
     * @public
     * @since 1.0.0
     */
    Shape.prototype.updateShape = function () {
        var s = this;
        // if (!s.visible) return;//这里不阻止
        if (!s.dirty)
            return;
        s.dirty = false;
        // s._boundsID++;//为了Container里calculateBounds的判断;//20211201注释下面s.texture.update()里会执行
        //更新缓存
        var cLen = s._command.length;
        var leftX;
        var leftY;
        var buttonRightX;
        var buttonRightY;
        var i;
        //确定是否有数据,如果有数据的话就计算出缓存图的宽和高
        var data;
        var lastX = 0;
        var lastY = 0;
        var lineWidth = 0;
        for (i = 0; i < cLen; i++) {
            data = s._command[i];
            if (data[0] == 1) {
                if (data[1] == "moveTo" || data[1] == "lineTo" || data[1] == "arcTo" || data[1] == "bezierCurveTo") {
                    if (leftX == undefined) {
                        leftX = data[2][0];
                    }
                    if (leftY == undefined) {
                        leftY = data[2][1];
                    }
                    if (buttonRightX == undefined) {
                        buttonRightX = data[2][0];
                    }
                    if (buttonRightY == undefined) {
                        buttonRightY = data[2][1];
                    }
                    if (data[1] == "bezierCurveTo") {
                        leftX = Math.min(leftX, data[2][0], data[2][2], data[2][4]);
                        leftY = Math.min(leftY, data[2][1], data[2][3], data[2][5]);
                        buttonRightX = Math.max(buttonRightX, data[2][0], data[2][2], data[2][4]);
                        buttonRightY = Math.max(buttonRightY, data[2][1], data[2][3], data[2][5]);
                        lastX = data[2][4];
                        lastY = data[2][5];
                    }
                    else {
                        leftX = Math.min(leftX, data[2][0]);
                        leftY = Math.min(leftY, data[2][1]);
                        buttonRightX = Math.max(buttonRightX, data[2][0]);
                        buttonRightY = Math.max(buttonRightY, data[2][1]);
                        lastX = data[2][0];
                        lastY = data[2][1];
                    }
                }
                else if (data[1] == "quadraticCurveTo") {
                    //求中点
                    var mid1X = (lastX + data[2][0]) * 0.5;
                    var mid1Y = (lastY + data[2][1]) * 0.5;
                    var mid2X = (data[2][0] + data[2][2]) * 0.5;
                    var mid2Y = (data[2][1] + data[2][3]) * 0.5;
                    if (leftX == undefined) {
                        leftX = mid1X;
                    }
                    if (leftY == undefined) {
                        leftY = mid1Y;
                    }
                    if (buttonRightX == undefined) {
                        buttonRightX = mid1X;
                    }
                    if (buttonRightY == undefined) {
                        buttonRightY = mid1Y;
                    }
                    leftX = Math.min(leftX, mid1X, mid2X, data[2][2]);
                    leftY = Math.min(leftY, mid1Y, mid2Y, data[2][3]);
                    buttonRightX = Math.max(buttonRightX, mid1X, mid2X, data[2][2]);
                    buttonRightY = Math.max(buttonRightY, mid1Y, mid2Y, data[2][3]);
                    lastX = data[2][2];
                    lastY = data[2][3];
                }
                else if (data[1] == "arc") {
                    var yuanPointX = data[2][0];
                    var yuanPointY = data[2][1];
                    var radio = data[2][2];
                    var yuanLeftX = yuanPointX - radio;
                    var yuanLeftY = yuanPointY - radio;
                    var yuanBRX = yuanPointX + radio;
                    var yuanBRY = yuanPointY + radio;
                    if (leftX == undefined) {
                        leftX = yuanLeftX;
                    }
                    if (leftY == undefined) {
                        leftY = yuanLeftY;
                    }
                    if (buttonRightX == undefined) {
                        buttonRightX = yuanBRX;
                    }
                    if (buttonRightY == undefined) {
                        buttonRightY = yuanBRY;
                    }
                    leftX = Math.min(leftX, yuanLeftX);
                    leftY = Math.min(leftY, yuanLeftY);
                    buttonRightX = Math.max(buttonRightX, yuanBRX);
                    buttonRightY = Math.max(buttonRightY, yuanBRY);
                }
            }
            else {
                if (data[1] == "lineWidth") {
                    if (lineWidth < data[2]) {
                        lineWidth = data[2];
                    }
                }
            }
        }
        if (leftX != undefined || lineWidth > 0) {
            if (leftX == undefined) {
                leftX = 0;
                leftY = 0;
            }
            leftX -= 20 + lineWidth >> 1;
            leftY -= 20 + lineWidth >> 1;
            buttonRightX += 20 + lineWidth >> 1;
            buttonRightY += 20 + lineWidth >> 1;
            var w = buttonRightX - leftX;
            var h = buttonRightY - leftY;
            // s.offsetX = leftX;
            // s.offsetY = leftY;
            // s._localBoundsSelf.x = leftX + 10;//下面anchorTexture的设置会更新（且还是原来的错误的纹理尺寸），s.texture.update()里也会更新了
            // s._localBoundsSelf.y = leftY + 10;
            // s._localBoundsSelf.width = w - 20;
            // s._localBoundsSelf.height = h - 20;
            var _canvas = s.canvas;
            var ctx = s.context;
            _canvas.width = w;
            _canvas.height = h;
            ctx.clearRect(0, 0, w, h);
            ctx.setTransform(1, 0, 0, 1, -leftX, -leftY);
            s._drawShape(ctx);
            //贴图锚点修改
            s.anchorTexture.set(-leftX / w, -leftY / h); //= { x: -leftX / w, y: -leftY / h };
        }
        else {
            s.canvas.width = 0;
            s.canvas.height = 0;
            // s.offsetX = 0;
            // s.offsetY = 0;
            // s._localBoundsSelf.clear();//下面anchorTexture的设置会更新（且还是原来的错误的纹理尺寸），s.texture.update()里也会更新了
            s.anchorTexture.set(0, 0); //= { x: 0, y: 0 };
        }
        //更新贴图
        s.texture.update();
        //这个先不管,上面的_localBoundsSelf等都已计算
        // s._onTextureUpdate();//更新回去anchorTexture修改时更新了用的时原先的canvas尺寸，20211201注释（texture.update()内会执行（监听一直在））
    };
    /**
     * @method _drawShape
     * @param ctx
     * @private
     * @return {void}
     */
    Shape.prototype._drawShape = function (ctx) {
        var s = this;
        var com = s._command;
        var cLen = com.length;
        var data;
        // let leftX: number = s.offsetX;
        // let leftY: number = s.offsetY;
        for (var i = 0; i < cLen; i++) {
            data = com[i];
            if (data[0] > 0) {
                var paramsLen = data[2].length;
                if (paramsLen == 0) {
                    ctx[data[1]]();
                }
                else if (paramsLen == 2) {
                    ctx[data[1]](data[2][0], data[2][1]);
                }
                else if (paramsLen == 4) {
                    ctx[data[1]](data[2][0], data[2][1], data[2][2], data[2][3]);
                }
                else if (paramsLen == 5) {
                    ctx[data[1]](data[2][0], data[2][1], data[2][2], data[2][3], data[2][4]);
                }
                else if (paramsLen == 6) {
                    var lx = data[2][4];
                    var ly = data[2][5];
                    if (data[0] == 2) {
                        //位图填充
                        // lx -= leftX;
                        // ly -= leftY;
                        //位图填充是也有矩阵，导致_drawShape之前设置的setTransform里的-leftX, -leftY无效，所以这里额外处理,待测试
                        lx += s.anchorTexture.x * s.canvas.width;
                        lx += s.anchorTexture.y * s.canvas.height;
                    }
                    ctx[data[1]](data[2][0], data[2][1], data[2][2], data[2][3], lx, ly);
                }
            }
            else {
                ctx[data[1]] = data[2];
            }
        }
    };
    /**
     * 重写hitTestPoint
     * @method  hitTestPoint
     * @param {Point} globalPoint
     * @param {boolean} isMouseEvent
     * @return {any}
     * @public
     * @since 1.0.0
     */
    Shape.prototype.hitTestPoint = function (globalPoint, isMouseEvent) {
        if (isMouseEvent === void 0) { isMouseEvent = false; }
        //更新shape
        this.updateShape();
        //直接用继承的，20211216修改
        return _super.prototype.hitTestPoint.call(this, globalPoint, isMouseEvent);
        // let s: Shape = this;
        // this.updateShape();//需要更新shape先
        // //直接继承
        // var hitResult = super.hitTestPoint(globalPoint, isMouseEvent)
        // //如果这样返回都没有，直接返回null
        // if (!hitResult) return null;
        // //如果不是自己，是子级的。直接返回子级
        // if (hitResult != s) return hitResult;
        // //如果不是像素级碰撞 直接返回自己
        // if (!s.hitTestByPixel) return s;
        // let p: Point = globalPoint;
        // //p要用到获取像素
        // if (isMouseEvent) p = s.globalToLocal(globalPoint);
        // let image = s._texture;
        // //无图数据返回null
        // if (!image || image.width == 0 || image.height == 0) return null;
        // // var backupCanvas = getBackupCanvas();
        // // backupCanvas.width = 1;
        // // backupCanvas.height = 1;
        // p.x -= s.offsetX;
        // p.y -= s.offsetY;
        // let ctx = getBackupCanvasCtx() //backupCanvas.getContext('2d');
        // ctx.setTransform(1, 0, 0, 1, 0, 0);//先移动位置，否则颜色清除有问题,原先修改尺寸就不用
        // ctx.clearRect(0, 0, 1, 1);
        // ctx.setTransform(1, 0, 0, 1, -p.x, -p.y);
        // ctx.drawImage(s.canvas, 0, 0);
        // //取imageData对象
        // var imageData = ctx.getImageData(0, 0, 1, 1);
        // //容错处理(暂时淘宝小程序bug，安卓有可能取到的imageData是undefined)，按照点击了返回
        // if (!imageData || !imageData.data) return s;
        // //像素透明度不为0；返回自己
        // if (imageData.data[3] > 0) return s;
        // return null
    };
    /**
     * 如果有的话,改变矢量对象的边框或者填充的颜色.
     * @method changeColor
     * @param {Object} infoObj
     * @param {string|any} infoObj.fillColor 填充颜色值，如"#fff" 或者 "rgba(255,255,255,1)"或者是Shape.getGradientColor()方法返回的渐变对象;
     * @param {string} infoObj.strokeColor 线条颜色值，如"#fff" 或者 "rgba(255,255,255,1)";
     * @param {number} infoObj.lineWidth 线条的粗细，如"1,2,3...";
     * @public
     * @since 1.0.2
     */
    Shape.prototype.changeColor = function (infoObj) {
        var s = this;
        var cLen = s._command.length;
        var c = s._command;
        for (var i = 0; i < cLen; i++) {
            if (c[i][0] == 0) {
                if (c[i][1] == "fillStyle" && infoObj.fillColor && c[i][2] != infoObj.fillColor) {
                    c[i][2] = infoObj.fillColor;
                    s.dirty = true;
                }
                if (c[i][1] == "strokeStyle" && infoObj.strokeColor && c[i][2] != infoObj.strokeColor) {
                    c[i][2] = infoObj.strokeColor;
                    s.dirty = true;
                }
                if (c[i][1] == "lineWidth" && infoObj.lineWidth && c[i][2] != infoObj.lineWidth) {
                    c[i][2] = infoObj.lineWidth;
                    s.dirty = true;
                }
            }
        }
    };
    /**
     * 计算自身盒子前要更新shape
     */
    // _calculateBounds() {
    //     this.updateShape();
    //     super._calculateBounds();
    // }
    //因为updateShape里的_boundId++不会影响calculateBounds里的判断，用不带_的继承，TODO待测试
    Shape.prototype.calculateBounds = function () {
        this.updateShape();
        //在舞台上，且渲染方式是webgl，且用过遮罩的，注意，临时解决webgl，shape的遮罩移动时不生效，待考虑更优雅的方式TODO
        if (this.stage && this.stage.renderObj.type == RENDERER_TYPE.WEBGL && this._isUsedToMask)
            this._boundsID++;
        _super.prototype.calculateBounds.call(this);
    };
    Shape.prototype._renderCanvas = function (renderer) {
        this.updateShape();
        _super.prototype._renderCanvas.call(this, renderer);
    };
    Shape.prototype._renderWebGL = function (renderer) {
        this.updateShape();
        _super.prototype._renderWebGL.call(this, renderer);
    };
    Shape.prototype.destroy = function () {
        //清除相应的数据引用
        var s = this;
        s._command = null;
        s._isBitmapStroke = null;
        s._isBitmapFill = null;
        _super.prototype.destroy.call(this);
    };
    return Shape;
}(Sprite));

var tempPoint$1 = new Point();
var tempPolygon = new Polygon();
/**
 * Mesh网格类，其实最优的是仿pixiV5和threejs用geometry和material
 * 简便起见，顶点，索引，uv都干一起吧
 * 用batch渲染
 */
var Mesh = /** @class */ (function (_super) {
    __extends(Mesh, _super);
    /**
     * @param {Texture} texture - 纹理
     * @param {Float32Array} [vertices] - 顶点，类型化数组，默认[0,0, 100,0, 100,100, 0,100]
     * @param {Float32Array} [uvs] - uv坐标，类型化数组，[0,0, 1,0, 1,1, 0,1]
     * @param {Uint16Array} [indices] - 索引，类型化数组，默认[0, 1, 3, 2]
     */
    function Mesh(texture, vertices, uvs, indices) {
        var _this = _super.call(this) || this;
        /**
         * 混色模式
         * @default BLEND_MODES.NORMAL
         */
        _this._blendMode = BLEND_MODES.NORMAL;
        _this._instanceType = "Mesh";
        /**
         * 赋值有问题，再处理
         */
        _this._texture = texture || Texture.EMPTY;
        _this._uvs = uvs || new Float32Array([
            0, 0,
            1, 0,
            1, 1,
            0, 1
        ]);
        _this._vertices = vertices || new Float32Array([
            0, 0,
            100, 0,
            100, 100,
            0, 100
        ]);
        _this._indices = indices || new Uint16Array([0, 1, 3, 2, 3, 1]);
        _this._vertexDirty = 0;
        //置为-1，确保计算
        _this._vertexId = -1;
        _this._localBoundsSelfId = -1;
        _this.blendMode = BLEND_MODES.NORMAL;
        _this.canvasPadding = 0;
        _this._tint = null;
        _this._tintRGB = null;
        _this.tint = 0xFFFFFF;
        _this._uvTransform = new TextureMatrix(_this._texture);
        //标记，至少更新一次
        _this._needRefresh = true;
        return _this;
    }
    Object.defineProperty(Mesh.prototype, "blendMode", {
        //以后修改
        get: function () {
            return this._blendMode;
        },
        /**
         * 很多效果暂时无效，再查原因，先不能设置吧
         */
        set: function (value) {
            // if (value != this._blendMode) this._blendMode = value
        },
        enumerable: false,
        configurable: true
    });
    /**
     * webgl渲染自身方法
     * @private
     * @param {WebGLRenderer} renderer
     */
    Mesh.prototype._renderWebGL = function (renderer) {
        //刷一次
        this.refresh();
        //计算全局顶点
        this.calculateVertices();
        renderer.batchManager.setObjectRenderer(renderer.plugins["batch"]);
        renderer.plugins["batch"].render(this);
    };
    /**
     * canvas渲染自身方法
     * @private
     * @param {CanvasRenderer} renderer
     */
    Mesh.prototype._renderCanvas = function (renderer) {
        this.refresh();
        renderer.plugins["mesh"].render(this);
    };
    /**
     * 纹理更新时触发
     * @private
     */
    Mesh.prototype._onTextureUpdate = function () {
        this._uvTransform.texture = this._texture;
        this._needRefresh = true;
    };
    /**
     * 重新计算uv，为了图集上的uv和自身uv
     */
    Mesh.prototype.multiplyUvs = function () {
        this._uvTransform.multiplyUvs(this._uvs);
    };
    /**
     * 就是为了_refresh
     * @param {boolean} [forceUpdate=false] 是否强制更新，默认false
     */
    Mesh.prototype.refresh = function (forceUpdate) {
        if (forceUpdate === void 0) { forceUpdate = false; }
        //贴图不可用，返回
        if (!this._texture || !this._texture.valid)
            return;
        if (this._uvTransform.update(forceUpdate) ||
            this._needRefresh ||
            forceUpdate) {
            this._refresh();
        }
    };
    /**
     * 子类重写，用来计算 顶点，uv，索引
     * @protected
     */
    Mesh.prototype._refresh = function () {
        /* empty */
    };
    /**
     * 计算一边全局的顶点
     */
    Mesh.prototype.calculateVertices = function () {
        //顶点没变，坐标没变，就返回
        if (this._vertexId === this._vertexDirty && this._transformID === this.transform._worldID)
            return;
        this._vertexId = this._vertexDirty;
        this._transformID = this.transform._worldID;
        if (this._vertices.length <= 2)
            return;
        if (!this._vertexData)
            this._vertexData = new Float32Array(this._vertices.length);
        var wt = this.transform.worldMatrix;
        var a = wt.a;
        var b = wt.b;
        var c = wt.c;
        var d = wt.d;
        var tx = wt.tx;
        var ty = wt.ty;
        var vertexData = this._vertexData;
        for (var i = 0; i < vertexData.length / 2; i++) {
            var x = this._vertices[(i * 2)];
            var y = this._vertices[(i * 2) + 1];
            vertexData[(i * 2)] = (a * x) + (c * y) + tx;
            vertexData[(i * 2) + 1] = (b * x) + (d * y) + ty;
        }
    };
    /**
     * 计算自己全局包围盒
     */
    Mesh.prototype._calculateBounds = function () {
        // TODO - we can cache local bounds and use them if they are dirty (like graphics)
        // this._bounds.addVertices(this.transform, this.vertices, 0, this.vertices.length);
        this.updateLocalBoundsSelf();
        var rect = this._localBoundsSelf;
        var matrix = this.transform.worldMatrix;
        matrix.transformPoint(rect.x, rect.y, DisplayObject._p1);
        matrix.transformPoint(rect.x + rect.width, rect.y, DisplayObject._p2);
        matrix.transformPoint(rect.x + rect.width, rect.y + rect.height, DisplayObject._p3);
        matrix.transformPoint(rect.x, rect.y + rect.height, DisplayObject._p4);
        Rectangle.createFromPoints(this._bounds, DisplayObject._p1, DisplayObject._p2, DisplayObject._p3, DisplayObject._p4);
    };
    /**
     * 更新自身包围盒
     * 通过原先的顶点数据玩，不经过transform
     */
    Mesh.prototype.updateLocalBoundsSelf = function () {
        if (this._localBoundsSelfId == this._vertexDirty)
            return;
        this._localBoundsSelfId = this._vertexDirty;
        //如果小于等于1个点清空
        if (this._vertices.length <= 2)
            this._localBoundsSelf.clear();
        Rectangle.createFromVertexData(this._localBoundsSelf, this._vertices);
    };
    /**
     *
     * @param point 全局点
     * @param isMouseEvent
     */
    Mesh.prototype.hitTestPoint = function (point, isMouseEvent) {
        if (isMouseEvent === void 0) { isMouseEvent = false; }
        //不可见，直接返回
        if (!this.visible)
            return null;
        var hitDisplayObject;
        //先检查子级，因为子级层级更高
        hitDisplayObject = _super.prototype.hitTestPoint.call(this, point, isMouseEvent);
        //子级已有，返回
        if (hitDisplayObject)
            return hitDisplayObject;
        //子级没有的话，为了可以不updateLocalBoundsSelf，判断一下
        if (isMouseEvent && !this.mouseEnable)
            return null;
        //再粗略检查自己，先计算自身盒子
        this.updateLocalBoundsSelf();
        //简单检测
        hitDisplayObject = this.displayObjectHitTestPoint(point, isMouseEvent);
        //如果在LocalBoundsSelf内，再继续查点组成的
        if (hitDisplayObject)
            return this.hitTestPointAccuratly(point, isMouseEvent);
        return null;
    };
    Mesh.prototype.hitTestPointAccuratly = function (point, isMouseEvent) {
        if (isMouseEvent) {
            this.globalToLocal(point, tempPoint$1);
        }
        else {
            tempPoint$1.set(point.x, point.y);
        }
        var vertices = this._vertices;
        var points = tempPolygon.points;
        var indices = this._indices;
        var len = this._indices.length;
        for (var i = 0; i + 2 < len; i += 3) {
            var ind0 = indices[i] * 2;
            var ind1 = indices[i + 1] * 2;
            var ind2 = indices[i + 2] * 2;
            points[0] = vertices[ind0];
            points[1] = vertices[ind0 + 1];
            points[2] = vertices[ind1];
            points[3] = vertices[ind1 + 1];
            points[4] = vertices[ind2];
            points[5] = vertices[ind2 + 1];
            if (tempPolygon.isPointIn(tempPoint$1))
                return this;
        }
        return null;
    };
    Object.defineProperty(Mesh.prototype, "texture", {
        /**
         * 纹理
         * @member {Texture}
         */
        get: function () {
            return this._texture;
        },
        set: function (value) {
            if (this._texture === value)
                return;
            this._texture = value;
            if (value) {
                // wait for the texture to load
                if (value.baseTexture.hasLoaded) {
                    this._onTextureUpdate();
                }
                else {
                    value.once('update', this._onTextureUpdate, this);
                }
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Mesh.prototype, "tint", {
        get: function () {
            return this._tint;
        },
        set: function (value) {
            if (value === this._tint)
                return;
            this._tint = value;
            this._tintRGB = (value >> 16) + (value & 0xff00) + ((value & 0xff) << 16);
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 销毁
     */
    Mesh.prototype.destroy = function () {
        _super.prototype.destroy.call(this);
        //相应texture移除监听
        this._texture.removeEventListener('update', this._onTextureUpdate, this);
        this._uvs = null;
        this._vertices = null;
        this._indices = null;
        this._vertexData = null;
    };
    return Mesh;
}(Container));

/**
 * @class
 * @extends Mesh
 *
 */
var Plane = /** @class */ (function (_super) {
    __extends(Plane, _super);
    /**
     * @param {Texture} texture - 纹理
     * @param {number} [verticesX=10] - x轴顶点数
     * @param {number} [verticesY=10] - y轴顶点数
     */
    function Plane(texture, verticesX, verticesY) {
        if (verticesX === void 0) { verticesX = 10; }
        if (verticesY === void 0) { verticesY = 10; }
        var _this = _super.call(this, texture) || this;
        _this.verticesX = verticesX;
        _this.verticesY = verticesY;
        _this.verticesX = verticesX || 10; //先留着吧，万一有传null，或0的
        _this.verticesY = verticesY || 10;
        _this.refresh();
        return _this;
    }
    /**
     * Refreshes plane coordinates
     *
     */
    Plane.prototype._refresh = function () {
        var texture = this.texture;
        var total = this.verticesX * this.verticesY;
        var verts = [];
        var uvs = [];
        var segmentsX = this.verticesX - 1;
        var segmentsY = this.verticesY - 1;
        var sizeX = texture.width / segmentsX;
        var sizeY = texture.height / segmentsY;
        for (var i = 0; i < total; i++) {
            var x = (i % this.verticesX);
            var y = ((i / this.verticesX) | 0);
            verts.push(x * sizeX, y * sizeY);
            uvs.push(x / segmentsX, y / segmentsY);
        }
        // console.log(indices)
        this._vertices = new Float32Array(verts);
        this._uvs = new Float32Array(uvs);
        this._indices = calculatePlaneIndices(this.verticesX, this.verticesY);
        this._vertexDirty++;
        this.multiplyUvs();
    };
    return Plane;
}(Mesh));
/**
 * 计算平面的索引
 * @param verticesX x轴上的顶点数量，最小2
 * @param verticesY y轴上的顶点数量，最小2
 */
function calculatePlaneIndices(verticesX, verticesY) {
    var segmentsX = verticesX - 1;
    var segmentsY = verticesY - 1;
    var totalSub = segmentsX * segmentsY;
    var indices = [];
    for (var i = 0; i < totalSub; i++) {
        var xpos = i % segmentsX;
        var ypos = (i / segmentsX) | 0;
        var value = (ypos * verticesX) + xpos;
        var value2 = (ypos * verticesX) + xpos + 1;
        var value3 = ((ypos + 1) * verticesX) + xpos;
        var value4 = ((ypos + 1) * verticesX) + xpos + 1;
        indices.push(value, value2, value3);
        indices.push(value2, value4, value3);
    }
    return new Uint16Array(indices);
}
// new Ripple(texutre, 50, 108, 3)
// class Ripple extends Plane {
//     /**
//      * 波源影响半径
//      */
//     private radius: number;
//     private oldNew: boolean;
//     private heightOld: number[][];
//     private heightNew: number[][];
//     private _verticesOri
//     /**
//      * 分段数
//      * @param segX 
//      * @param segY 
//      */
//     constructor(texture: Texture, segX: number = 10, segY: number = 10, radius: number = 5) {
//         super(texture, segX, segY)
//         this.radius = radius;
//         this.oldNew = false;
//         this.heightOld = [];
//         this.heightNew = [];
//         for (var i = 0; i < this.verticesX; i++) {
//             this.heightOld[i] = [];
//             this.heightNew[i] = [];
//             for (var j = 0; j < this.verticesY; j++) {
//                 this.heightOld[i][j] = 0;
//                 this.heightNew[i][j] = 0;
//             }
//         }
//         //拷贝一个源数据
//         this._verticesOri = this._vertices.slice();
//         let fun = (a, e) => {
//             var x1 = Math.round(e.localX / (texture.width / (this.verticesX - 1)));
//             var y1 = Math.round(e.localY / (texture.height / (this.verticesY - 1)));
//             // console.log(x1,y1)
//             this.disturb(x1, y1, a);
//         }
//         this.addEventListener(MouseEvent.MOUSE_MOVE, fun.bind(this, "m"), this)
//         this.addEventListener(MouseEvent.MOUSE_DOWN, fun.bind(this, "d"), this)
//     }
//     getEnergy(e, r, d) {
//         return e * (1 - d / r);
//     };
//     refractionOff(i, j, rect) {
//         var xl = i - 1;
//         var xr = i + 1;
//         if (i == 0) xl = 0;
//         if (i == this.verticesX - 1) xr = this.verticesX - 1;
//         var yu = j - 1;
//         var yd = j + 1;
//         if (j == 0) yu = 0
//         if (j == this.verticesY - 1) yd = this.verticesY - 1
//         var xoff = rect[i][yu] - rect[i][yd];
//         var yoff = rect[xr][j] - rect[xl][j];
//         return { xoff: xoff, yoff: yoff }
//     };
//     distance(a, b) {
//         var x = b.x - a.x, y = b.y - a.y;
//         return Math.sqrt(x * x + y * y);
//     };
//     getAmplitude(i, j, rect) {
//         var xl = i - 1;
//         var xr = i + 1;
//         if (i == 0) xl = 0;
//         if (i == this.verticesX - 1) xr = this.verticesX - 1;
//         var yu = j - 1;
//         var yd = j + 1;
//         if (j == 0) yu = 0;
//         if (j == this.verticesY - 1) yd = this.verticesY - 1
//         return (rect[i][yu] + rect[i][yd] + rect[xl][j] + rect[xr][j]) / 2
//     };
//     disturb(i, j, type = "d") {
//         var rectsv = this.heightOld;
//         var rectsNewv = this.heightNew;
//         var xmin = i - this.radius;
//         if (xmin < 0) xmin = 0;
//         var xmax = i + this.radius;
//         if (xmax > this.verticesX - 1) xmax = this.verticesX - 1;
//         var ymin = j - this.radius;
//         if (ymin < 0) ymin = 0;
//         var ymax = j + this.radius;
//         if (ymax > this.verticesY - 1) ymax = this.verticesY - 1;
//         for (var m = xmin; m <= xmax; m++) {
//             for (var n = ymin; n <= ymax; n++) {
//                 var dist = this.distance({ x: i, y: j }, { x: m, y: n });
//                 if (dist <= this.radius) {
//                     if (type == "d") {
//                         rectsv[m][n] += this.getEnergy(64, this.radius, dist);
//                         rectsNewv[m][n] += this.getEnergy(64, this.radius, dist);
//                     } else {
//                         rectsv[m][n] += this.getEnergy(16, this.radius, dist);
//                         rectsNewv[m][n] += this.getEnergy(16, this.radius, dist);
//                     }
//                 }
//             }
//         }
//     };
//     update() {
//         super.update();
//         for (var i = 0; i < this.verticesX; i++) {
//             for (var j = 0; j < this.verticesY; j++) {
//                 var rectsv = this.heightOld;
//                 var rectsNewv = this.heightNew;
//                 var d;
//                 var off;
//                 if (this.oldNew) {
//                     d = this.getAmplitude(i, j, rectsv);
//                     d -= rectsNewv[i][j];
//                     d -= d / 64;
//                     rectsNewv[i][j] = d;
//                     off = this.refractionOff(i, j, this.heightNew);
//                 } else {
//                     d = this.getAmplitude(i, j, rectsNewv);
//                     d -= rectsv[i][j];
//                     d -= d / 64;
//                     rectsv[i][j] = d;
//                     off = this.refractionOff(i, j, this.heightOld);
//                 }
//                 var index = j * this.verticesX + i;
//                 this._vertices[index * 2] = this._verticesOri[index * 2] - off.xoff;
//                 this._vertices[index * 2 + 1] = this._verticesOri[index * 2 + 1] - off.yoff;
//                 // this.vets[index].z = d;
//             }
//         }
//         this.oldNew = !this.oldNew;
//         //确保会更新
//         this._vertexDirty++
//     };
// }

//提前计算好的索引
var indicesNN = calculatePlaneIndices(4, 4);
/**
 * The NineSlicePlane allows you to stretch a texture using 9-slice scaling. The corners will remain unscaled (useful
 * for buttons with rounded corners for example) and the other areas will be scaled horizontally and or vertically
 *
 *```js
 * let Plane9 = new NineSlicePlane(Texture.fromImage('BoxWithRoundedCorners.png'), 15, 15, 15, 15);
 *  ```
 * <pre>
 *      A                          B
 *    +---+----------------------+---+
 *  C | 1 |          2           | 3 |
 *    +---+----------------------+---+
 *    |   |                      |   |
 *    | 4 |          5           | 6 |
 *    |   |                      |   |
 *    +---+----------------------+---+
 *  D | 7 |          8           | 9 |
 *    +---+----------------------+---+

 *  When changing this objects width and/or height:
 *     areas 1 3 7 and 9 will remain unscaled.
 *     areas 2 and 8 will be stretched horizontally
 *     areas 4 and 6 will be stretched vertically
 *     area 5 will be stretched both horizontally and vertically
 * </pre>
 *
 * @class
 * @extends Mesh 继承MESH
 *
 */
var NineSlicePlane = /** @class */ (function (_super) {
    __extends(NineSlicePlane, _super);
    /**
     * @param {Texture} texture 纹理
     * @param {int} [leftWidth=10] size of the left vertical bar (A)
     * @param {int} [topHeight=10] size of the top horizontal bar (C)
     * @param {int} [rightWidth=10] size of the right vertical bar (B)
     * @param {int} [bottomHeight=10] size of the bottom horizontal bar (D)
     */
    function NineSlicePlane(texture, leftWidth, topHeight, rightWidth, bottomHeight) {
        if (leftWidth === void 0) { leftWidth = 10; }
        if (topHeight === void 0) { topHeight = 10; }
        if (rightWidth === void 0) { rightWidth = 10; }
        if (bottomHeight === void 0) { bottomHeight = 10; }
        var _this = _super.call(this, texture) || this;
        //考虑对于未加载好的图片怎么处理吧，肯定需要加在onTextureUpdate的
        _this._origWidth = texture.orig.width;
        _this._origHeight = texture.orig.height;
        _this._width = _this._origWidth;
        _this._height = _this._origHeight;
        _this._leftWidth = leftWidth;
        _this._rightWidth = rightWidth;
        _this._topHeight = topHeight;
        _this._bottomHeight = bottomHeight;
        //计算索引，完全不用变，所以提前计算
        _this._indices = indicesNN;
        //顶点数量长度可以确定先
        _this._vertices = new Float32Array(4 * 4 * 2);
        //uv长度也可以确定先
        _this._uvs = new Float32Array(4 * 4 * 2);
        _this.refresh(true);
        return _this;
    }
    /**
     * 更新水平顶点
     */
    NineSlicePlane.prototype.updateHorizontalVertices = function () {
        var vertices = this._vertices;
        var h = this._topHeight + this._bottomHeight;
        var scale = this._height > h ? 1.0 : this._height / h;
        vertices[9] = vertices[11] = vertices[13] = vertices[15] = this._topHeight * scale;
        vertices[17] = vertices[19] = vertices[21] = vertices[23] = this._height - (this._bottomHeight * scale);
        vertices[25] = vertices[27] = vertices[29] = vertices[31] = this._height;
    };
    /**
     * 更新垂直顶点
     */
    NineSlicePlane.prototype.updateVerticalVertices = function () {
        var vertices = this._vertices;
        var w = this._leftWidth + this._rightWidth;
        var scale = this._width > w ? 1.0 : this._width / w;
        vertices[2] = vertices[10] = vertices[18] = vertices[26] = this._leftWidth * scale;
        vertices[4] = vertices[12] = vertices[20] = vertices[28] = this._width - (this._rightWidth * scale);
        vertices[6] = vertices[14] = vertices[22] = vertices[30] = this._width;
    };
    /**
     * canvas渲染
     * 考虑是否用缓存，不然每次相当于9次绘制，到时应该是集成到一个插件里的
     * @private
     * @param {CanvasRenderer} renderer
     */
    NineSlicePlane.prototype._renderCanvas = function (renderer) {
        var context = renderer.context;
        context.globalAlpha = this._worldAlpha;
        renderer.setBlendMode(this.blendMode);
        var transform = this.worldMatrix;
        context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty);
        var base = this.texture.baseTexture;
        var textureSource = base.source;
        var w = base.width;
        var h = base.height;
        this.drawSegment(context, textureSource, w, h, 0, 1, 10, 11);
        this.drawSegment(context, textureSource, w, h, 2, 3, 12, 13);
        this.drawSegment(context, textureSource, w, h, 4, 5, 14, 15);
        this.drawSegment(context, textureSource, w, h, 8, 9, 18, 19);
        this.drawSegment(context, textureSource, w, h, 10, 11, 20, 21);
        this.drawSegment(context, textureSource, w, h, 12, 13, 22, 23);
        this.drawSegment(context, textureSource, w, h, 16, 17, 26, 27);
        this.drawSegment(context, textureSource, w, h, 18, 19, 28, 29);
        this.drawSegment(context, textureSource, w, h, 20, 21, 30, 31);
    };
    /**
     * 绘制某块平面
     * 至少1像素
     * @private
     * @param {CanvasRenderingContext2D} context - 上下文
     * @param {CanvasImageSource} textureSource - 图片标签
     * @param {number} w - 图片宽度
     * @param {number} h - 图片高度
     * @param {number} x1 - x index 1
     * @param {number} y1 - y index 1
     * @param {number} x2 - x index 2
     * @param {number} y2 - y index 2
     */
    NineSlicePlane.prototype.drawSegment = function (context, textureSource, w, h, x1, y1, x2, y2) {
        // otherwise you get weird results when using slices of that are 0 wide or high.
        var uvs = this._uvs;
        var vertices = this._vertices;
        var sw = (uvs[x2] - uvs[x1]) * w;
        var sh = (uvs[y2] - uvs[y1]) * h;
        var dw = vertices[x2] - vertices[x1];
        var dh = vertices[y2] - vertices[y1];
        // make sure the source is at least 1 pixel wide and high, otherwise nothing will be drawn.
        if (sw < 1) {
            sw = 1;
        }
        if (sh < 1) {
            sh = 1;
        }
        // make sure destination is at least 1 pixel wide and high, otherwise you get
        // lines when rendering close to original size.
        if (dw < 1) {
            dw = 1;
        }
        if (dh < 1) {
            dh = 1;
        }
        context.drawImage(textureSource, uvs[x1] * w, uvs[y1] * h, sw, sh, vertices[x1], vertices[y1], dw, dh);
    };
    Object.defineProperty(NineSlicePlane.prototype, "width", {
        /**
         * 宽度
         * @member {number}
         */
        get: function () {
            return this._width;
        },
        /**
         * 不再修改缩放，设置后会修改uv和顶点
         */
        set: function (value) {
            this._width = value;
            this._needRefresh = true;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(NineSlicePlane.prototype, "height", {
        /**
         * 高度
         * @member {number}
         */
        get: function () {
            return this._height;
        },
        /**
         * 不再修改缩放，设置后会修改uv和顶点
         */
        set: function (value) {
            this._height = value;
            this._needRefresh = true;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(NineSlicePlane.prototype, "leftWidth", {
        /**
         * The width of the left column
         *
         * @member {number}
         */
        get: function () {
            return this._leftWidth;
        },
        set: function (value) {
            this._leftWidth = value;
            this._needRefresh = true;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(NineSlicePlane.prototype, "rightWidth", {
        /**
         * The width of the right column
         *
         * @member {number}
         */
        get: function () {
            return this._rightWidth;
        },
        set: function (value) {
            this._rightWidth = value;
            this._needRefresh = true;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(NineSlicePlane.prototype, "topHeight", {
        /**
         * The height of the top row
         *
         * @member {number}
         */
        get: function () {
            return this._topHeight;
        },
        set: function (value) {
            this._topHeight = value;
            this._needRefresh = true;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(NineSlicePlane.prototype, "bottomHeight", {
        /**
         * The height of the bottom row
         *
         * @member {number}
         */
        get: function () {
            return this._bottomHeight;
        },
        set: function (value) {
            this._bottomHeight = value;
            this._needRefresh = true;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 刷新所有坐标
     */
    NineSlicePlane.prototype._refresh = function () {
        var uvs = this._uvs;
        var texture = this.texture;
        this._origWidth = texture.orig.width;
        this._origHeight = texture.orig.height;
        var _uvw = 1.0 / this._origWidth;
        var _uvh = 1.0 / this._origHeight;
        uvs[0] = uvs[8] = uvs[16] = uvs[24] = 0;
        uvs[1] = uvs[3] = uvs[5] = uvs[7] = 0;
        uvs[6] = uvs[14] = uvs[22] = uvs[30] = 1;
        uvs[25] = uvs[27] = uvs[29] = uvs[31] = 1;
        uvs[2] = uvs[10] = uvs[18] = uvs[26] = _uvw * this._leftWidth;
        uvs[4] = uvs[12] = uvs[20] = uvs[28] = 1 - (_uvw * this._rightWidth);
        uvs[9] = uvs[11] = uvs[13] = uvs[15] = _uvh * this._topHeight;
        uvs[17] = uvs[19] = uvs[21] = uvs[23] = 1 - (_uvh * this._bottomHeight);
        this.updateHorizontalVertices();
        this.updateVerticalVertices();
        this._vertexDirty++;
        this.multiplyUvs();
    };
    return NineSlicePlane;
}(Mesh));

//  function testRope() {
//     let count = 0;
//     // build a rope!
//     const ropeLength = 918 / 20;
//     const points = [];
//     for (let i = 0; i < 20; i++) {
//         points.push(new Point(i * ropeLength, 0));
//     }
//     const strip = new Rope(Texture.fromImage("snake.png"), points);
//     strip.x = -459;
//     const snakeContainer = new Container();
//     snakeContainer.x = 400;
//     snakeContainer.y = 300;
//     snakeContainer.scale.set(800 / 1100, 800 / 1100);
//     this.addChild(snakeContainer);
//     snakeContainer.addChild(strip);
//     this.addEventListener(Event.ENTER_FRAME, () => {
//         count += 0.1;
//         for (let i = 0; i < points.length; i++) {
//             points[i].y = Math.sin((i * 0.5) + count) * 30;
//             points[i].x = i * ropeLength + Math.cos((i * 0.3) + count) * 20;
//         }
//         strip.refreshVertices()
//     }, this)
// }
/**
 * 为了能加入批处理，不用TRIANGLE_STRIP方式渲染(有需要看v4版本的pixi)，还是用TRIANGLE
 *```js
 * for (let i = 0; i < 20; i++) {
 *     points.push(new Point(i * 50, 0));
 * };
 * let rope = new Rope(Texture.fromImage("snake.png"), points);
 *  ```
 *
 *
 */
var Rope = /** @class */ (function (_super) {
    __extends(Rope, _super);
    /**
     * @param {Texture} texture
     * @param {Point[]} points
     */
    function Rope(texture, points) {
        var _this = _super.call(this, texture) || this;
        _this.points = points;
        _this._vertices = new Float32Array(points.length * 4);
        _this._uvs = new Float32Array(points.length * 4);
        _this._indices = new Uint16Array((points.length - 1) * 6);
        _this.textureHeight = texture.height;
        _this.refresh(true);
        _this.refreshVertices();
        return _this;
    }
    /**
     * 计算索引和uv，和顶点计算的要分开
     */
    Rope.prototype._refresh = function () {
        var points = this.points;
        //没点，或贴图uv为空
        if (points.length < 1 || !this.texture._uvs)
            return;
        //如果顶点数量有变
        if (this._vertices.length / 4 !== points.length) {
            this._vertices = new Float32Array(points.length * 4);
            this._uvs = new Float32Array(points.length * 4);
            this._indices = new Uint16Array((points.length - 1) * 6);
        }
        var uvs = this._uvs;
        var indices = this._indices;
        uvs[0] = 0;
        uvs[1] = 0;
        uvs[2] = 0;
        uvs[3] = 1;
        // indices[0] = 0;
        // indices[1] = 1;
        var total = points.length;
        for (var i = 1; i < total; i++) {
            // time to do some smart drawing!
            var index = i * 4;
            var amount = i / (total - 1);
            uvs[index] = amount;
            uvs[index + 1] = 0;
            uvs[index + 2] = amount;
            uvs[index + 3] = 1;
        }
        var indexCount = 0;
        for (var i = 0; i < total - 1; i++) {
            var index = i * 2;
            indices[indexCount++] = index;
            indices[indexCount++] = index + 1;
            indices[indexCount++] = index + 2;
            indices[indexCount++] = index + 2;
            indices[indexCount++] = index + 1;
            indices[indexCount++] = index + 3;
        }
        this.multiplyUvs();
        // this.refreshVertices();
    };
    /**
     * 根据points刷新顶点
     */
    Rope.prototype.refreshVertices = function () {
        var points = this.points;
        //
        if (points.length < 1)
            return;
        //如果points数量修改过，去执行_refresh
        if (this._vertices.length / 4 !== points.length) {
            this._refresh(); //里面肯定会把_vertices的长度矫正
            this.refreshVertices();
            return;
        }
        var lastPoint = points[0];
        var nextPoint;
        var perpX = 0;
        var perpY = 0;
        // this.count -= 0.2;
        var vertices = this._vertices;
        var total = points.length;
        for (var i = 0; i < total; i++) {
            var point = points[i];
            var index = i * 4;
            if (i < points.length - 1) {
                nextPoint = points[i + 1];
            }
            else {
                nextPoint = point;
            }
            perpY = -(nextPoint.x - lastPoint.x);
            perpX = nextPoint.y - lastPoint.y;
            var perpLength = Math.sqrt((perpX * perpX) + (perpY * perpY));
            var num = this.textureHeight / 2; // (20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio;
            perpX /= perpLength;
            perpY /= perpLength;
            perpX *= num;
            perpY *= num;
            vertices[index] = point.x + perpX;
            vertices[index + 1] = point.y + perpY;
            vertices[index + 2] = point.x - perpX;
            vertices[index + 3] = point.y - perpY;
            lastPoint = point;
        }
        //标记修改
        this._vertexDirty++;
    };
    Rope.prototype.update = function () {
        _super.prototype.update.call(this);
        //自动更新顶点，或者纹理高度有修改
        if (this.autoUpdateVertices || this.textureHeight !== this.texture.height) {
            this.textureHeight = this.texture.height;
            this.refreshVertices();
        }
    };
    return Rope;
}(Mesh));

// 作为将显示对象导出成图片的render渲染器，所以无法截取3d场景，3d场景暂时自己处理显隐裁切，用toDataURL获取，以后考虑改成WebglRenderer
var _dRender = null;
var _dCanvas;
var tempMatrix$2 = new Matrix();
/**
 * 将显示对象转成base64的图片数据
 * 淘宝小程序上有问题，不用，canvas的toDataURL被删了
 * @method toDisplayDataURL
 * @static
 * @param {DisplayObject} obj 显示对象
 * @param {Rectangle} rect 需要裁切的区域，默认不裁切
 * @param {Object} typeInfo {type:"png"}  或者 {type:"jpeg",quality:100}  png格式不需要设置quality，jpeg 格式需要设置quality的值 从1-100
 * @param {number} bgColor 十六进制颜色值如 0xffffff 默认值为空的情况下，jpeg格式的话就是黑色底，png格式的话就是透明底,暂时无效
 * @return {string} base64格式数据
 * @example
 *      toDisplayDataURL(DisplayObj, {
 *               x: 0,
 *               y: 32,
 *               width: 441,
 *               height: 694
 *       }, {
 *               type: "jpeg"//数据类型jpeg/png
 *               quality: 90//图片质量值1-100,png格式不需要设置quality
 *       }, 0xffffff);
 *
 */
function toDisplayDataURL(obj, rect, typeInfo /*: { type: "png" | "jpeg", quality?: number }*/, bgColor) {
    if (rect === void 0) { rect = null; }
    if (typeInfo === void 0) { typeInfo /*: { type: "png" | "jpeg", quality?: number }*/ = null; }
    var bounds = obj.getLocalBounds();
    var w = rect ? rect.width : bounds.width;
    var h = rect ? rect.height : bounds.height;
    var x = rect ? rect.x : bounds.x;
    var y = rect ? rect.y : bounds.y;
    if (!_dRender) {
        var canvas = createCanvas();
        canvas.width = w;
        canvas.height = h;
        _dCanvas = canvas;
        _dRender = new CanvasRenderer(canvas.getContext("2d"), w, h);
    }
    else {
        _dCanvas.width = w;
        _dCanvas.height = h;
    }
    if (!typeInfo) {
        typeInfo = { type: "png" };
    }
    //以防万一，刷一次
    obj.transform.updateLocalMatrix();
    tempMatrix$2.copy(obj.transform.localMatrix);
    tempMatrix$2.invert();
    tempMatrix$2.tx -= x;
    tempMatrix$2.ty -= y;
    _dRender.render(obj, null, tempMatrix$2);
    //因为上面render会修改obj的全局矩阵，保证会被修改回去
    obj.transform._parentID = -1;
    // document.body.appendChild(_canvasBuffer.baseTexture.source)
    return _dCanvas.toDataURL("image/" + typeInfo.type, typeInfo.quality);
}
//利用离屏纹理，暂时背景色无效，因为canvasRender暂时不对离屏纹理填充背景色，以后有需要再说
// let _canvasBuffer: RenderTexture = null;
/**
 * 将显示对象转成base64的图片数据
 * @method toDisplayDataURL
 * @static
 * @param {DisplayObject} obj 显示对象
 * @param {Rectangle} rect 需要裁切的区域，默认不裁切
 * @param {Object} typeInfo {type:"png"}  或者 {type:"jpeg",quality:100}  png格式不需要设置quality，jpeg 格式需要设置quality的值 从1-100
 * @param {number} bgColor 十六进制颜色值如 0xffffff 默认值为空的情况下，jpeg格式的话就是黑色底，png格式的话就是透明底,
 * @return {string} base64格式数据
 */
/*function toDisplayDataURL(obj: DisplayObject, rect: Rectangle = null, typeInfo: any = null, bgColor: number = 0x000000): string {
    var bounds = obj.getLocalBounds();
    let w: number = rect ? rect.width : bounds.width;
    let h: number = rect ? rect.height : bounds.height;
    let x: number = rect ? rect.x : bounds.x;
    let y: number = rect ? rect.y : bounds.y;
    if (!_canvasBuffer) {
        _canvasBuffer = RenderTexture.create(w, h);
    } else {
        _canvasBuffer.resize(w, h)
    }
    if (!_dRender) {
        _dRender = new CanvasRenderer({});
    }
    if (!typeInfo) {
        typeInfo = { type: "png" };
    }
    if (typeInfo.type == "png") {
        _dRender.transparent = true;
    } else {
        _dRender.transparent = false;
        _dRender.backgroundColor = bgColor
    }
    obj.transform.updateLocalMatrix();
    tempMatrix.copy(obj.transform.localMatrix);
    tempMatrix.invert();
    tempMatrix.tx -= x;
    tempMatrix.ty -= y;
    _dRender.render(obj, _canvasBuffer, tempMatrix);
    return _canvasBuffer.baseTexture.source["toDataURL"]("image/" + typeInfo.type, typeInfo.quality);
};*/

//文本canvas上xy的偏移量
var padding = 10;
/**
 * 动态文本类
 * @class TextField
 * @extends Sprite
 * @since 1.0.0
 * @public
 */
var TextField = /** @class */ (function (_super) {
    __extends(TextField, _super);
    // offsetX: number;
    // offsetY: number;
    function TextField() {
        var _this = _super.call(this) || this;
        _this._textAlpha = 1;
        _this._textAlign = TEXT_ALIGN.LEFT;
        _this._verticalAlign = VERTICAL_ALIGN.UP;
        _this._textWidth = 0;
        _this._textHeight = 0;
        _this._lineType = TEXT_lINETYPE.SINGLE;
        _this._text = "";
        _this._font = "Arial";
        _this._size = 12;
        _this._fillColor = "#ffffff";
        _this._strokeColor = "#ffffff";
        _this._stroke = 0;
        _this._italic = false;
        _this._bold = false;
        _this._border = false;
        _this.realLines = [];
        _this._instanceType = "TextField";
        //ios直接
        // if (osType == "ios") {
        var canvas = createCanvas();
        // canvas.width = 3;
        // canvas.height = 3;
        // if (osType == "ios") {
        canvas.width = canvas.height = 3;
        // } else {//现在只能用canvas2d渲染，所以不能用imageData了，等修复了安卓canvas尺寸问题再改
        //     canvas.width = 300;
        //     canvas.height = 150;
        // }
        _this.texture = Texture.fromCanvas(canvas, "textCanvas");
        _this.canvas = canvas;
        _this.context = canvas.getContext("2d");
        // }
        // //安卓的不能改变离屏canvas的尺寸，所以用750*750的，取imageData
        // else {
        //     if (!TextField.shareCanvas) {
        //         TextField.shareCanvas = createCanvas();
        //         TextField.shareCanvas.width = TextField.shareCanvas.height = 750;
        //         TextField.shareContext = TextField.shareCanvas.getContext("2d");
        //     }
        //     var baseTexture = new BaseTexture({
        //         _data: [],
        //         width: 0,
        //         height: 0,
        //         type: "text",
        //         path: null
        //     });
        //     this.texture = new Texture(baseTexture);
        //     this.canvas = TextField.shareCanvas;
        //     this.context = TextField.shareContext;
        // }
        //baseTexture已自动缓存，把texture也缓存，key textCanvas+num  和baseTexture的一致
        Texture.addToCache(_this.texture, _this.texture.baseTexture.textureCacheIds[0]);
        _this.dirty = true;
        return _this;
    }
    Object.defineProperty(TextField.prototype, "textAlpha", {
        get: function () {
            return this._textAlpha;
        },
        /**
         * @property textAlpha
         * @since 2.0.0
         * @public
         */
        set: function (value) {
            if (this._textAlpha != value) {
                this._textAlpha = value;
                this.dirty = true;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(TextField.prototype, "textAlign", {
        get: function () {
            return this._textAlign;
        },
        /**
         * 文本的水平对齐方式 left center right
         * 设置过textHeight才有效，如果是多行的，对排版有作用
         * @property textAlign
         * @public
         * @since 1.0.0
         * @type {string}
         * @default left
         */
        set: function (value) {
            if (this._textAlign != value) {
                this._textAlign = value;
                this.dirty = true;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(TextField.prototype, "verticalAlign", {
        get: function () {
            return this._verticalAlign;
        },
        /**
         * 垂直对齐方式
         * 设置过textHeight才有效
         */
        set: function (value) {
            if (this._verticalAlign != value) {
                this._verticalAlign = value;
                this.dirty = true;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(TextField.prototype, "textWidth", {
        get: function () {
            if (this._textWidth) {
                //有就这个
                return this._textWidth;
            }
            else {
                //没有就计算出的给width，还是
                this.updateText();
                return this.width - padding * 2;
            }
        },
        /**
         * 文本的宽，
         * @property textWidth
         * @public
         * @since 1.0.0
         * @type {number}
         * @default 0
         */
        set: function (value) {
            if (this._textWidth != value) {
                this._textWidth = value;
                this.dirty = true;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(TextField.prototype, "textHeight", {
        get: function () {
            if (this._textHeight) {
                //有就这个
                return this._textHeight;
            }
            else {
                //没有就计算出的给height，还是
                this.updateText();
                return this.height - padding * 2;
            }
        },
        /**
         * 文本的总高度，设置过能进行垂直适配，
         * 设置过的话，超出textHeight会被裁切
         * @property textHeight
         * @public
         * @since 1.0.0
         * @type {number}
         * @default 0
         */
        set: function (value) {
            if (this._textHeight != value) {
                this._textHeight = value;
                this.dirty = true;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(TextField.prototype, "lineHeight", {
        get: function () {
            return this._lineHeight || Math.round(this.size * 1.4);
        },
        /**
         * 行高，每行文本的高度，不设置就是size的1.4倍，和css的对应
         */
        set: function (value) {
            if (this._lineHeight != value) {
                this._lineHeight = value;
                this.dirty = true;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(TextField.prototype, "lineType", {
        get: function () {
            return this._lineType;
        },
        // /**
        //  * 行间距
        //  * @property lineSpacing
        //  * @public
        //  * @since 1.0.0
        //  * @param {number} value
        //  */
        // public set lineSpacing(value: number) {
        //     if (this._lineSpacing != value) {
        //         this._lineSpacing = value;
        //         this.dirty = true;
        //     };
        // }
        // public get lineSpacing(): number {
        //     return this._lineSpacing;
        // }
        // private _lineSpacing: number = 14;
        /**
         * 文本类型,单行还是多行 single multi
         * @property lineType
         * @public
         * @since 1.0.0
         * @type {string} 两种 single和multi
         * @default single
         */
        set: function (value) {
            if (this._lineType != value) {
                this._lineType = value;
                this.dirty = true;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(TextField.prototype, "text", {
        get: function () {
            return this._text;
        },
        /**
         * 文本内容
         * @property text
         * @type {string}
         * @public
         * @default ""
         * @since 1.0.0
         */
        set: function (value) {
            if (this._text != value) {
                this._text = value;
                this.dirty = true;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(TextField.prototype, "font", {
        get: function () {
            return this._font;
        },
        /**
         * 文本的css字体样式
         * @property font
         * @public
         * @since 1.0.0
         * @type {string}
         * @default 12px Arial
         */
        set: function (value) {
            if (this._font != value) {
                this._font = value;
                this.dirty = true;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(TextField.prototype, "size", {
        get: function () {
            return this._size;
        },
        /**
         * 文本的size
         * @property size
         * @public
         * @since 1.0.0
         * @type {number}
         * @default 12
         */
        set: function (value) {
            if (this._size != value) {
                this._size = value;
                this.dirty = true;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(TextField.prototype, "fillColor", {
        get: function () {
            return this._fillColor;
        },
        /**
         * 文本的填充颜色值,比如字符串"#ffffff"或十六进制数字0xffffff
         * @property fillColor
         * @type {string|number}
         * @public
         * @since 1.0.0
         * @default #fff
         */
        set: function (value) {
            if (typeof (value) == "number") {
                value = hex2string(value);
            }
            if (this._fillColor != value) {
                this._fillColor = value;
                this.dirty = true;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(TextField.prototype, "strokeColor", {
        get: function () {
            return this._strokeColor;
        },
        /**
         * 文本的描边颜色值,比如字符串"#ffffff"或十六进制数字0xffffff
         * @property strokeColor
         * @type {string|number}
         * @public
         * @since 1.0.0
         * @default #fff
         */
        set: function (value) {
            if (typeof (value) == "number") {
                value = hex2string(value);
            }
            if (this._strokeColor != value) {
                this._strokeColor = value;
                this.dirty = true;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(TextField.prototype, "stroke", {
        get: function () {
            return this._stroke;
        },
        /**
         * 文本描边宽度,为0则不描边
         * @property stroke
         * @public
         * @since
         * @default 0
         * @type {number}
         */
        set: function (value) {
            if (this._stroke != value) {
                this._stroke = value;
                this.dirty = true;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(TextField.prototype, "italic", {
        get: function () {
            return this._italic;
        },
        /**
         * 文本是否倾斜
         * @property italic
         * @public
         * @since
         * @default false
         * @type {boolean}
         */
        set: function (value) {
            if (this._italic != value) {
                this._italic = value;
                this.dirty = true;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(TextField.prototype, "bold", {
        get: function () {
            return this._bold;
        },
        /**
         * 文本是否加粗
         * @property bold
         * @public
         * @since
         * @default false
         * @type {boolean}
         */
        set: function (value) {
            if (this._bold != value) {
                this._bold = value;
                this.dirty = true;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(TextField.prototype, "border", {
        get: function () {
            return this._border;
        },
        /**
         * 设置或获取是否有边框
         * @property property
         * @param {boolean} show true或false
         * @public
         * @since 1.0.6
         */
        set: function (value) {
            if (this._border != value) {
                this._border = value;
                this.dirty = true;
            }
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 设置文本在canvas里的渲染样式
     * @method _prepContext
     * @param ctx
     * @private
     * @since 1.0.0
     */
    TextField.prototype._prepContext = function (ctx) {
        var s = this;
        var font = s.size || 12;
        font += "px ";
        font += s.font;
        //font-weight:bold;font-style:italic;
        if (s._bold) {
            font = "bold " + font;
        }
        if (s._italic) {
            font = "italic " + font;
        }
        ctx.font = font;
        ctx.textAlign = s._textAlign || TEXT_ALIGN.LEFT;
        //暂时没开放
        ctx.textBaseline = "middle"; //"top";
        ctx.fillStyle = getRGBA(s._fillColor, s._textAlpha);
        //确保描边样式
        ctx.lineJoin = "round";
    };
    /**
     * 获取当前文本中单行文字的宽，注意是文字的不是文本框的宽
     * 暂不用，可能有问题
     * @method getTextWidth
     * @param {number} lineIndex 获取的哪一行的高度 默认是第1行
     * @since 2.0.0
     * @public
     * @return {number}
     */
    TextField.prototype.getTextWidth = function (lineIndex) {
        if (lineIndex === void 0) { lineIndex = 0; }
        var s = this;
        s.updateText();
        // let can = s.canvas;
        var ctx = s.context;
        var obj = ctx.measureText(s.realLines[lineIndex]);
        return obj.width;
    };
    Object.defineProperty(TextField.prototype, "lines", {
        /**
         * @property _lines 获取当前文本行数
         * @type {number}
         * @public
         * @readonly
         * @since 2.0.0
         */
        get: function () {
            return this.realLines.length;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 获取文本宽
     * @method _getMeasuredWidth
     * @param text
     * @return {number}
     * @private
     * @since 1.0.0
     */
    TextField.prototype._getMeasuredWidth = function (text) {
        //如果不是淘宝环境，就用canvas的api measureText
        /*if (getEnv() == "web")*/ return this.context.measureText(text).width;
    };
    /**
     * 根据宽度截取文本，
     * 注意调用前需要_prepContext，保证文本属性，否则测量文本宽度有误
     * @param str 需要截取的文本
     * @param textWidth 截取宽度，不传默认使用本身设置的文本宽度，如未设置不处理
     */
    TextField.prototype._cutLines = function (str, textWidth, isOnlyOne) {
        if (textWidth === void 0) { textWidth = this._textWidth; }
        if (isOnlyOne === void 0) { isOnlyOne = false; }
        var s = this, lines = [];
        var lineStr = str[0];
        var strLen = str.length, wordW;
        for (var j = 1; j < strLen; j++) {
            //测量连续字符，而不是单个字符
            wordW = s._getMeasuredWidth(lineStr + str[j]);
            if (wordW > textWidth) {
                //加一个
                lines.push(lineStr);
                if (isOnlyOne)
                    return lines;
                //重新赋值
                lineStr = str[j];
            }
            else {
                lineStr += str[j];
            }
        }
        if (lineStr)
            lines.push(lineStr);
        return lines;
    };
    /**
     * 更新文本，主要重画canvas，回调是很有问题的
     */
    TextField.prototype.updateText = function ( /*callback?*/) {
        // if (callback) this.callback = callback;
        // let backupCanvasContext = getBackupCanvasContext();
        // if (!backupCanvasContext) return
        // if (backupCanvasContext["isBusy"]) return;
        var s = this;
        if (!s.dirty) {
            // this.callback && this.callback();
            // this.callback = null
            return;
        }
        s.dirty = false;
        // s._boundsID++;//为了Container里calculateBounds的判断;//下面s.texture.update()内会执行监听内容_onTextureUpdate
        //强转字符
        s._text += "";
        //如果没有文本
        if (!s._text) {
            // if (osType == "ios") {
            s.canvas.width = 0;
            s.canvas.height = 0;
            // } else {//暂时不能用sourceData形式，所以和上面效果一样
            //     s.texture.baseTexture.source.width = 0;
            //     s.texture.baseTexture.source.height = 0;
            // }
            // s._localBoundsSelf.clear();//下面s.texture.update()内会执行监听内容_onTextureUpdate
            s.anchorTexture = { x: 0, y: 0 };
            s.texture.update();
            return;
        }
        var can = s.canvas;
        var ctx = s.context;
        // ctx.save();
        var hardLines = s._text.toString().split(/(?:\r\n|\r|\n)/);
        var realLines = [];
        s.realLines = realLines;
        s._prepContext(ctx); //因为不用canvas的api量文本宽度，所以这里执行不重要
        var textWidth = s._textWidth;
        // let lineH = s._lineSpacing + s.size;
        //单行文本时
        if (s._text.indexOf("\n") < 0 && //没有换行符
            s._text.indexOf("\r") < 0 && //没有换行符
            s._text.indexOf("\r\n") < 0 && //没有换行符
            s.lineType == TEXT_lINETYPE.SINGLE //确定单行
        ) {
            realLines[realLines.length] = hardLines[0];
            var str = hardLines[0];
            var lineW = s._getMeasuredWidth(str);
            //如果没设置过textWidth就取lineW
            textWidth = textWidth || lineW;
            //如果设置过textWidth的。截取文本
            if (lineW > textWidth) {
                // let w = s._getMeasuredWidth(str[0]);
                // let lineStr = str[0];
                // let wordW = 0;
                // let strLen = str.length;
                // for (let j = 1; j < strLen; j++) {
                //     wordW = s._getMeasuredWidth(str[j])//ctx.measureText(str[j]).width;
                //     w += wordW;
                //     if (w > textWidth) {
                //         realLines[0] = lineStr;
                //         break;
                //     } else {
                //         lineStr += str[j];
                //     }
                // }
                //用新的方法
                realLines[0] = s._cutLines(str, textWidth, true)[0];
            }
        }
        else {
            //textWidth取每行最大值，如果没设置过textWidth
            if (!textWidth) {
                for (var i = 0, l = hardLines.length; i < l; i++) {
                    var str = hardLines[i];
                    if (!str)
                        continue;
                    textWidth = Math.max(s._getMeasuredWidth(str), textWidth);
                    //下面加else了，这里记录真实每行文本
                    realLines[realLines.length] = str;
                }
            }
            //设置过_textWidth的，需要检查每行文本宽度，该换行的换行
            else {
                for (var i = 0, l = hardLines.length; i < l; i++) {
                    var str = hardLines[i];
                    if (!str)
                        continue;
                    // let w = s._getMeasuredWidth(str[0]);
                    // let lineStr = str[0];
                    // let wordW = 0;
                    // let strLen = str.length;
                    // for (let j = 1; j < strLen; j++) {
                    //     wordW = s._getMeasuredWidth(str[j])//ctx.measureText(str[j]).width;
                    //     w += wordW;
                    //     if (w > textWidth) {
                    //         realLines[realLines.length] = lineStr;
                    //         lineStr = str[j];
                    //         w = wordW;
                    //     } else {
                    //         lineStr += str[j];
                    //     }
                    // }
                    // realLines[realLines.length] = lineStr;
                    //用新的方法
                    realLines.push.apply(realLines, s._cutLines(str, textWidth));
                }
            }
        }
        var lineH = this.lineHeight;
        var trueHeight = lineH * realLines.length;
        var maxH = s._textHeight || trueHeight;
        var maxW = textWidth;
        var tx = 0;
        if (s._textAlign == TEXT_ALIGN.CENTER) {
            tx = maxW * 0.5;
        }
        else if (s._textAlign == TEXT_ALIGN.RIGHT) {
            tx = maxW;
        }
        var canWidth = maxW + padding * 2;
        var canHeight = maxH + padding * 2;
        can.width = canWidth;
        can.height = canHeight;
        ctx.setTransform(1, 0, 0, 1, 0, 0); //在不能修改尺寸的时候，否则尺寸改变，上下文会初始化
        ctx.clearRect(0, 0, can.width, can.height); //安卓貌似无效，文案重叠了再处理，或者等修复了尺寸问题就好了
        if (s.border) {
            ctx.beginPath();
            ctx.strokeStyle = "#000";
            ctx.lineWidth = 1;
            ctx.strokeRect(padding + 0.5, padding + 0.5, maxW, maxH);
            ctx.closePath();
        }
        ctx.setTransform(1, 0, 0, 1, tx + padding, padding /* - 10*/);
        s._prepContext(ctx);
        // let lineH = s._lineSpacing + s.size;
        //如果有_textHeight,就需要应用竖直对齐
        var upY = 0;
        if (s._textHeight) {
            //跟trueHeight比较
            if (s._verticalAlign == VERTICAL_ALIGN.MIDDLE) {
                upY = (s._textHeight - trueHeight) * 0.5;
            }
            else if (s._verticalAlign == VERTICAL_ALIGN.DOWN || s._verticalAlign == VERTICAL_ALIGN.BOTTOM) {
                upY = s._textHeight - trueHeight;
            }
        }
        //还没测试是否已修复
        getEnv() == "tb" && (upY -= 4);
        for (var i = 0; i < realLines.length; i++) {
            var oy = (lineH /*- s.size*/) / 2;
            var ox = 0;
            if (s.stroke) {
                ctx.strokeStyle = s.strokeColor;
                ctx.lineWidth = s.stroke * 2;
                ctx.strokeText(realLines[i], ox, upY + i * lineH + oy /*, maxW*/);
            }
            ctx.fillText(realLines[i], ox, upY + i * lineH + oy /*, maxW*/); //考虑去掉这个maxW
        }
        // //offset用_anchorTexture代替
        // s.offsetX = -padding;
        // s.offsetY = -padding;
        // console.log(can)
        this.anchorTexture = { x: (padding + 0.5) / canWidth, y: padding / canHeight };
        // if (osType == "ios") {
        s.texture.update();
        // s._onTextureUpdate();//上面s.texture.update()会执行，监听一直在
        // document.body.appendChild(s.canvas)
        // } else {
        //     var imgData = ctx.getImageData(0, 0, canWidth, canHeight)
        //     var data = {
        //         _data: new Uint8Array(imgData.data),
        //         width: canWidth,
        //         height: canHeight,
        //         type: "text",
        //         path: null
        //     }
        //     s.texture.baseTexture._sourceChange(data);
        //     s._onTextureUpdate();
        // }
    };
    /**
     * 为了计算包围盒，需要计算一边文本，
     * 重写calculateBounds不好，应该只改_calculateBounds，考虑_boundID，以后再说，和shape的一样
     * 暂时只有两个类重写了calculateBounds，Shape和TextField
     */
    TextField.prototype.calculateBounds = function () {
        this.updateText();
        _super.prototype.calculateBounds.call(this);
    };
    //暂时没用
    TextField.prototype._renderCanvas = function (renderer) {
        this.updateText();
        _super.prototype._renderCanvas.call(this, renderer);
    };
    TextField.prototype._renderWebGL = function (renderer) {
        this.updateText();
        _super.prototype._renderWebGL.call(this, renderer);
    };
    TextField.prototype.destroy = function () {
        this.canvas = null;
        this.context = null;
        _super.prototype.destroy.call(this);
        //todo
    };
    return TextField;
}(Sprite));

// import { osType } from "../const";
/**
 * 可编辑文本
 */
var EditableText = /** @class */ (function (_super) {
    __extends(EditableText, _super);
    function EditableText() {
        var _this = _super.call(this) || this;
        _this._prompt = "Please input";
        _this._promptColor = "#eeeeee";
        _this._textColor = "#000000";
        /**
         * 输入的内容
         */
        _this._inputValue = "";
        _this._instanceType = "EditableText";
        var s = _this;
        var remove = function () {
            //失去焦点
            s.htmlElement && s.htmlElement.blur();
            //隐藏
            s.htmlElement.style.display = "none";
            //赋值
            if (s.htmlElement.value) {
                s.text = s.htmlElement.value;
                s.fillColor = s.textColor;
            }
            else {
                s.text = s.prompt;
                s.fillColor = s.promptColor;
            }
            //记录一下需要
            s._inputValue = s.htmlElement.value || "";
            window.scrollTo(0, 0);
        };
        _this.addEventListener(MouseEvent.CLICK, function (e) {
            s.initElement();
            //font包括字体和大小
            s.htmlElement.style.font = s.size + "px " + s.font;
            s.htmlElement.style.color = s.textColor;
            s.htmlElement.style.textAlign = s.textAlign;
            //     s.htmlElement.setAttribute("class", "inputTextFor");
            //    .inputTextFor:: -webkit - input - placeholder {
            //         text - align: center;
            //     }
            s.htmlElement.style.height = s.textHeight + "px";
            s.htmlElement.style.width = s.textWidth + "px";
            //如果文案不是默认的
            // if (s.text !== s.prompt) s.htmlElement.value = s.text;//这样判断还是可能有问题，TODO
            if (s.htmlElement.value != s._inputValue) {
                s.htmlElement.value = s._inputValue;
            }
            s.text = "";
            s.htmlElement.style.display = "block";
            s.htmlElement.selectionStart = s._inputValue.length;
            s.htmlElement.selectionEnd = s._inputValue.length;
            s.htmlElement.focus();
            var mtx = s.transform.worldMatrix;
            var d = s.stage["_dpi"] || s.stage["dpi"]; //devicePixelRatio || 1;//用舞台的,能点击肯定有舞台,所以不做存在判断
            // console.log(mtx)
            //位置
            s.htmlElement.style.transform = s.htmlElement.style.webkitTransform = "matrix(" + (mtx.a / d).toFixed(4) + "," + (mtx.b / d).toFixed(4) + "," + (mtx.c / d).toFixed(4) + "," + (mtx.d / d).toFixed(4) + "," + (mtx.tx / d).toFixed(4) + "," + (mtx.ty / d).toFixed(4) + ")";
            s.stage.once(MouseEvent.MOUSE_UP, remove);
        });
        return _this;
    }
    Object.defineProperty(EditableText.prototype, "prompt", {
        /**
         * 未输入文本时显示的文字
         */
        get: function () {
            return this._prompt;
        },
        set: function (value) {
            if (this._prompt != value) {
                this._prompt = value;
                this["dirty"] = true;
                //如果无输入文本直接修改
                if ( /*!this.htmlElement || !this.htmlElement.value*/!this._inputValue) {
                    this.text = this._prompt;
                }
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(EditableText.prototype, "promptColor", {
        /**
         * 未输入文本时显示文字的颜色
         */
        get: function () {
            return this._promptColor;
        },
        set: function (value) {
            if (this._promptColor != value) {
                this._promptColor = value;
                this["dirty"] = true;
                //如果无输入文本直接修改
                if ( /*!this.htmlElement || !this.htmlElement.value*/!this._inputValue) {
                    this.fillColor = this._promptColor;
                }
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(EditableText.prototype, "textColor", {
        /**
         * 文本颜色，不用fillColor为了和父类区分
         * 输入文本时的颜色
         */
        get: function () {
            return this._textColor;
        },
        set: function (value) {
            if (this._textColor != value) {
                this._textColor = value;
                this["dirty"] = true;
                //如果又文本直接修改
                if ( /*this.htmlElement && this.htmlElement.value*/this._inputValue) {
                    this.fillColor = this._textColor;
                }
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(EditableText.prototype, "inputValue", {
        /**
         * 获取输入框内容
         */
        get: function () {
            // return this.htmlElement && this.htmlElement.value || (this.text != this._prompt ? this.text : "")
            return this._inputValue;
        },
        set: function (v) {
            v = v || "";
            //有就加上，无碍
            if (this.htmlElement)
                this.htmlElement.value = v;
            //如果v不存在就用默认文案
            this.text = v ? v : this._prompt;
            //如果v不存在就用默认颜色
            this.fillColor = v ? this.textColor : this._promptColor;
            //记录一下，这个是准确的
            this._inputValue = v;
        },
        enumerable: false,
        configurable: true
    });
    EditableText.prototype.initElement = function () {
        var s = this;
        if (s.htmlElement)
            return;
        s.htmlElement = document.createElement("input");
        var htmlElement = s.htmlElement, style = htmlElement.style;
        htmlElement.type = "input";
        style.position = "absolute";
        style.display = "none";
        //@ts-ignore
        style.transformOrigin = style.WebkitTransformOrigin = style.webkitTransformOrigin = "0 0 0";
        style.outline = "none";
        style.borderWidth = "thin";
        style.borderColor = "#000";
        //ios得加
        style.boxSizing = "border-box";
        style.padding = "0";
        style.margin = "0";
        //默认文案
        htmlElement.placeholder = "";
        /////////////////////设置边框//////////////
        style.borderStyle = "none";
        style.backgroundColor = "transparent";
        // s.htmlElement.style.borderStyle = "inset";
        // s.htmlElement.style.backgroundColor = "#fff";
        //color:blue; text-align:center"
        // if (this.inputType == 2) {
        //     this.htmlElement.style.lineHeight = lineSpacing + "px";
        // }
        // s.stage.rootDiv.insertBefore(s.htmlElement, s.stage.rootDiv.childNodes[0]);
        //TODO到时需要修改，记录下,stage加上canvas索引，
        var divParent = s.stage["canvas"].parentNode;
        if (divParent) {
            divParent.insertBefore(htmlElement, divParent.childNodes[0]);
        }
        else {
            document.body.appendChild(htmlElement);
        }
        //添加
        htmlElement.onblur = function (e) {
            if (getOsType() == "ios") {
                //部分app里的webview有兼容问题用window.scrollTo(0, 0)
                window.scrollTo({ top: 0, left: 0, behavior: "smooth" });
            }
            //抛出事件
            if (s.hasEventListener(Event.BLUR))
                s.dispatchEvent(Event.BLUR, e);
        };
        //输入事件
        htmlElement.oninput = function (e) {
            //抛出原生的input的事件
            // if (s.hasEventListener(Event.INPUT)) s.dispatchEvent(Event.INPUT, e)
            setTimeout(function () {
                if (htmlElement.selectionStart == htmlElement.selectionEnd) { //避免中文输入法
                    s._inputValue = htmlElement.value || "";
                    if (s.hasEventListener(Event.INPUT))
                        s.dispatchEvent(Event.INPUT, e);
                }
            }, 0);
        };
        //聚焦事件
        htmlElement.onfocus = function (e) {
            //抛出原生的聚焦的事件
            if (s.hasEventListener(Event.FOCUS))
                s.dispatchEvent(Event.FOCUS, e);
        };
        // //输入事件
        // let inputLock = false;
        // htmlElement.oninput = function (e) {
        //     if (!inputLock) {
        //         _onInput(e);
        //     }
        // };
        // htmlElement.addEventListener('compositionstart', function () {
        //     inputLock = true;
        // });
        // htmlElement.addEventListener('compositionend', function () {
        //     inputLock = false;
        //     if (!inputLock) {
        //         _onInput(e);
        //     }
        // });
        // function _onInput(e) {
        //     setTimeout(function () {
        //         if (htmlElement.selectionStart == htmlElement.selectionEnd) {
        //             s._inputValue = htmlElement.value;
        //             if (s.hasEventListener(Event.INPUT)) s.dispatchEvent(Event.INPUT, e)
        //         }
        //     }, 0);
        // }
    };
    EditableText.prototype.destroy = function () {
        //从dom节点移除
        if (this.htmlElement && this.htmlElement.parentNode) {
            this.htmlElement.parentNode.removeChild(this.htmlElement);
            this.htmlElement = null;
        }
        _super.prototype.destroy.call(this);
    };
    return EditableText;
}(TextField));

/**
 * 纯dom的输入文本,待测试
 * 输入,密码,文本区域
 */
var InputText = /** @class */ (function (_super) {
    __extends(InputText, _super);
    /**
     * @method InputText
     * @public
     * @since 1.0.0
     * @param {number} inputType 0 input 1 password 2 multiline
     * @example
     *      var inputText=new InputText();
     *      inputText.initInfo('aa','#ffffff','left',14,'微软雅黑',100,20);
     */
    function InputText(inputType) {
        if (inputType === void 0) { inputType = 0; }
        var _this = _super.call(this) || this;
        /**
         * 输入文本的类型.
         * @property inputType
         * @public
         * @since 1.0.0
         * @type {number} 0 input 1 password 2 mulit
         * @default 0
         */
        _this.inputType = 0;
        /**
         * 在手机端是否需要自动收回软键盘，在pc端此参数无效
         * @property isAutoDownKeyBoard
         * @type {boolean}
         * @since 1.0.3
         * @default true
         */
        _this.isAutoDownKeyBoard = true;
        var input = null;
        var s = _this;
        s._instanceType = "InputText";
        if (inputType < 2) {
            input = document.createElement("input");
            input.type = InputText._inputTypeList[inputType];
        }
        else {
            input = document.createElement("textarea");
            input.style.resize = "none";
            input.style.overflow = "hidden";
        }
        s.inputType = inputType;
        var remove = function () {
            if (s.isAutoDownKeyBoard && getOsType() != "pc") {
                s.htmlElement && s.htmlElement.blur();
                window.scrollTo(0, 0);
            }
        }.bind(s);
        s.addEventListener(Event.REMOVED_FROM_STAGE, function (e) {
            s.stage.removeEventListener(MouseEvent.MOUSE_UP, remove);
        });
        s.addEventListener(Event.ADDED_TO_STAGE, function (e) {
            //点击stage任何地方都失去焦点
            s.stage.addEventListener(MouseEvent.MOUSE_UP, remove);
        });
        s.init(input);
        return _this;
    }
    /**
     * 初始化输入文本
     * @method init
     * @param htmlElement
     * @public
     * @return {void}
     * @since 1.0.0
     */
    InputText.prototype.init = function (htmlElement) {
        _super.prototype.init.call(this, htmlElement);
        //默认设置
        var s = this;
        s.htmlElement.style.outline = "none";
        s.htmlElement.style.borderWidth = "thin";
        s.htmlElement.style.borderColor = "#000";
    };
    /**
     * 被始化输入文件的一些属性
     * @method initInfo
     * @public
     * @since 1.0.0
     * @param {string} text 默认文字
     * @param {string}color 文字颜色
     * @param {string}align 文字的对齐方式
     * @param {number}size  文字大小
     * @param {string}font  文字所使用的字体
     * @param {number}textWidth 文本宽
     * @param {number}textHeight 文本高
     * @param {number}lineHeight 如果是多行,请设置行高
     * @param {boolean}showBorder 是否需要显示边框
     */
    InputText.prototype.initInfo = function (text, color, align, size, font, textWidth, textHeight, lineHeight, showBorder) {
        if (showBorder === void 0) { showBorder = false; }
        var s = this;
        s.htmlElement.placeholder = text;
        //font包括字体和大小
        s.htmlElement.style.font = size + "px " + (font || "Arial");
        s.htmlElement.style.color = color;
        s.htmlElement.style.textAlign = align;
        /////////////////////设置边框//////////////
        s.border = showBorder;
        //color:blue; text-align:center"
        s.textWidth = textWidth;
        s.textHeight = textHeight;
        if (s.inputType == 2) {
            s.htmlElement.style.lineHeight = lineHeight + "px";
        }
    };
    Object.defineProperty(InputText.prototype, "lineHeight", {
        get: function () {
            return parseInt(this.htmlElement.style.lineHeight);
        },
        /**
         * @property lineHeight
         * @public
         * @since 2.0.0
         * @param {number} value
         */
        set: function (value) {
            this.htmlElement.style.lineHeight = value + "px";
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(InputText.prototype, "bold", {
        get: function () {
            return this.htmlElement.style.fontWeight == "bold";
        },
        /**
         * 设置文本是否为粗体
         * @property bold
         * @param {boolean} bold true或false
         * @public
         * @since 1.0.3
         */
        set: function (bold) {
            var ss = this.htmlElement.style;
            if (bold) {
                ss.fontWeight = "bold";
            }
            else {
                ss.fontWeight = "normal";
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(InputText.prototype, "italic", {
        get: function () {
            return this.htmlElement.style.fontStyle == "italic";
        },
        /**
         * 设置文本是否倾斜
         * @property italic
         * @param {boolean} italic true或false
         * @public
         * @since 1.0.3
         */
        set: function (italic) {
            var s = this.htmlElement.style;
            if (italic) {
                s.fontStyle = "italic";
            }
            else {
                s.fontStyle = "normal";
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(InputText.prototype, "textHeight", {
        get: function () {
            return parseInt(this.htmlElement.style.height);
        },
        /**
         * 文本的行高
         * @property textHeight
         * @public
         * @since 1.0.0
         * @type {number}
         * @default 0
         */
        set: function (value) {
            this.htmlElement.style.height = value + "px";
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(InputText.prototype, "textWidth", {
        get: function () {
            return parseInt(this.htmlElement.style.width);
        },
        /**
         * 文本的宽
         * @property textWidth
         * @public
         * @since 1.0.0
         * @type {number}
         * @default 0
         */
        set: function (value) {
            this.htmlElement.style.width = value + "px";
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(InputText.prototype, "color", {
        get: function () {
            return this.htmlElement.style.color;
        },
        /**
         * 设置文本颜色
         * @property color
         * @param {boolean} italic true或false
         * @public
         * @since 1.0.3
         */
        set: function (value) {
            var ss = this.htmlElement.style;
            ss.color = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(InputText.prototype, "border", {
        get: function () {
            return this.htmlElement.style.borderStyle != "none";
        },
        /**
         * 设置或获取是否有边框
         * @property property
         * @param {boolean} show true或false
         * @public
         * @since 1.0.3
         */
        set: function (show) {
            var s = this;
            if (show) {
                s.htmlElement.style.borderStyle = "inset";
                s.htmlElement.style.backgroundColor = "#fff";
            }
            else {
                s.htmlElement.style.borderStyle = "none";
                s.htmlElement.style.backgroundColor = "transparent";
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(InputText.prototype, "text", {
        /**
         * 获取或设置输入文本的值
         * 之前的getText 和setText 已废弃
         * @property text
         * @public
         * @since 1.0.3
         * @return {string}
         */
        get: function () {
            var s = this;
            if (s.htmlElement) {
                return s.htmlElement.value;
            }
        },
        set: function (value) {
            var s = this;
            if (s.htmlElement) {
                s.htmlElement.value = value;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(InputText.prototype, "maxCharacters", {
        /**
         * 输入文本的最大输入字数
         * @public
         * @since 1.1.0
         * @property maxCharacters
         * @return {number}
         */
        get: function () {
            var l = this.htmlElement.getAttribute("maxlength");
            if (l === null) {
                return 0;
            }
            else {
                return l;
            }
        },
        set: function (value) {
            this.htmlElement.setAttribute("maxlength", value);
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 转换为动态文本，位置上下会有偏差，再说，基本用于截图时，需要截到输入文本时
     * @param textField
     */
    InputText.prototype.convertToTextField = function (textField) {
        if (!this.htmlElement || !this.text)
            return null;
        textField = textField || new TextField();
        textField.fillColor = this.color;
        textField.text = this.text;
        textField.size = parseInt(this.htmlElement.style.font.split("px")[0]);
        textField.textAlign = this.htmlElement.style.textAlign;
        textField.bold = this.bold;
        textField.italic = this.italic;
        textField.textWidth = this.textWidth;
        textField.lineType = this.inputType == 2 ? TEXT_lINETYPE.MULTI : TEXT_lINETYPE.SINGLE;
        textField.position.copy(this.position);
        textField.scale.copy(this.scale);
        textField.rotation = this.rotation;
        return textField;
    };
    /**
     * @property _inputTypeList
     * @static
     * @type {string[]}
     * @private
     * @since 2.0.0
     */
    InputText._inputTypeList = ["input", "password", "textarea"];
    return InputText;
}(FloatDisplay));

/**
 * 单位图字缓存
 */
var bitmapTextSinglePool = [];
/**
 * 位图文字
 * 暂不做通用，以后再说，否则回收问题
 */
var BitmapText = /** @class */ (function (_super) {
    __extends(BitmapText, _super);
    /**
     *
     * @param textures 0到9的贴图
     */
    function BitmapText(textures) {
        var _this = _super.call(this) || this;
        _this._textAlign = TEXT_ALIGN.CENTER;
        _this._verticalAlign = VERTICAL_ALIGN.MIDDLE;
        _this._gap = 0;
        _this.textures = textures;
        return _this;
    }
    Object.defineProperty(BitmapText.prototype, "textAlign", {
        /**
         * 水平对齐方式，默认居中
         * 改变x坐标原点
         */
        get: function () {
            return this._textAlign;
        },
        set: function (value) {
            if (this._textAlign !== value) {
                this._textAlign = value;
                this.adaptate();
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BitmapText.prototype, "verticalAlign", {
        /**
         * 垂直居中方式，默认居中
         * 改变y坐标原点
         */
        get: function () {
            return this._verticalAlign;
        },
        set: function (value) {
            if (this._verticalAlign !== value) {
                this._verticalAlign = value;
                this.adaptate();
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BitmapText.prototype, "gap", {
        /**
         * 文字间隙，为了有些文本不能紧贴（切图问题），可设置负数解决
         */
        get: function () {
            return this._gap;
        },
        set: function (value) {
            if (this._gap != value) {
                this._gap = value;
                this.adaptate();
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BitmapText.prototype, "text", {
        get: function () {
            return this._text;
        },
        /**
         * 设置文本
         */
        set: function (value) {
            if (value === this._text)
                return;
            this._text = value;
            var arr = value || [];
            //
            for (var i = 0; i < arr.length; i++) {
                if (this.children[i]) {
                    //先用完原先$children里的
                    this.children[i]["text"] = arr[i];
                }
                else {
                    //如果没有就
                    var o = bitmapTextSinglePool.shift();
                    if (!o) {
                        o = new BitmapTextSingle(this.textures);
                    }
                    else {
                        o.reset(this.textures);
                    }
                    o.text = arr[i];
                    this.addChild(o);
                }
            }
            //如果多了，去掉后面的，回收
            if (this.children.length > arr.length) {
                //移除后序
                for (var i = this.children.length - 1; i >= arr.length; i--) {
                    var c = this.children[i];
                    this.removeChild(c);
                    bitmapTextSinglePool.push(c);
                }
            }
            //适配
            this.adaptate();
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 适配，
     */
    BitmapText.prototype.adaptate = function () {
        if (!this.children.length)
            return;
        var len = this.children.length;
        //算总长度
        var sum = 0;
        for (var m = 0; m < len; m++) {
            sum += this.children[m].width;
        }
        sum += (len - 1) * this._gap;
        //算出左边第一个元素的位置
        var left;
        if (this._textAlign == TEXT_ALIGN.LEFT) {
            left = 0;
        }
        else if (this._textAlign == TEXT_ALIGN.RIGHT) {
            left = -sum;
        }
        else {
            left = -sum / 2;
        }
        var temSum = 0;
        for (var i = 0; i < this.children.length; i++) {
            this.children[i].x = left + temSum;
            temSum += this.children[i].width + this._gap;
        }
        //垂直居中，找出高度最大的图片
        // var maxH = 0;
        // for (var m = 0; m < len; m++) {
        //     maxH = Math.max(maxH, this.children[m].height)
        // }
        // var up: number;
        // if (this._verticalAlign == VERTICAL_ALIGN.UP) {
        //     up = 0
        // }
        // else if (this._verticalAlign == VERTICAL_ALIGN.DOWN) {
        //     up = -maxH
        // } else {
        //     up = -maxH / 2
        // }
        // for (var i = 0; i < this.children.length; i++)this.children[i].y = up;
        var up = 0;
        if (this._verticalAlign == VERTICAL_ALIGN.DOWN || this._verticalAlign == VERTICAL_ALIGN.BOTTOM) {
            up = -1;
        }
        else if (this._verticalAlign == VERTICAL_ALIGN.MIDDLE) {
            up = -1 / 2;
        }
        this.children.forEach(function (c) {
            c.y = c.height * up;
        });
    };
    return BitmapText;
}(Container));
/**
 * 位图字，单个
 */
var BitmapTextSingle = /** @class */ (function (_super) {
    __extends(BitmapTextSingle, _super);
    /**
     *
     * @param textures 贴图表，{"0":texture1,"1":texture2,".":texture3}
     */
    function BitmapTextSingle(textures) {
        var _this = _super.call(this) || this;
        _this.textures = textures;
        return _this;
    }
    Object.defineProperty(BitmapTextSingle.prototype, "text", {
        get: function () {
            return this._text;
        },
        set: function (value) {
            // if (value == this._text) return;
            this._text = value;
            this.texture = this.textures[this._text];
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 替换资源，基本不用吧应该
     * @param textures
     */
    BitmapTextSingle.prototype.reset = function (textures) {
        this.textures = textures;
    };
    return BitmapTextSingle;
}(Sprite));

/**
 * 根据基础纹理和图集数据创建纹理图集，会进全局缓存
 * @param {BaseTexture} baseTexture
 * @param {Dict<ITextureSheetFrameData>} altaData 图集数据，一般是用pack_textures生成的数据
 * @return {Dict<Texture>} 返回贴图集。不常用
 */
function createTextureSheet(baseTexture, altaData) {
    var frames = altaData;
    var frameKeys = Object.keys(frames);
    var frameIndex = 0;
    //要返回的贴图集合
    var textures = {};
    while (frameIndex < frameKeys.length) {
        //名字
        var i = frameKeys[frameIndex];
        //数据
        var data = frames[i];
        //切图上的数据
        var frame = null;
        //裁切的数据
        var trim = null;
        //贴图原始尺寸
        var orig = new Rectangle(0, 0, Math.floor(data.sw), Math.floor(data.sh));
        //如果旋转过
        if (data.ro) {
            frame = new Rectangle(Math.floor(data.x), Math.floor(data.y), Math.floor(data.h), Math.floor(data.w));
        }
        else {
            frame = new Rectangle(Math.floor(data.x), Math.floor(data.y), Math.floor(data.w), Math.floor(data.h));
        }
        //如果是被截掉过透明边界的 ,,加上如果和原始尺寸不一致也是裁切
        if (data.ox || data.oy || data.w != data.sw || data.h != data.sh) {
            //其实就是在orig上切图，偏移
            trim = new Rectangle(Math.floor(data.ox), Math.floor(data.oy), Math.floor(data.w), Math.floor(data.h));
        }
        var texture = new Texture(baseTexture, frame, orig, trim, data.ro ? 2 : 0);
        //缓存下
        Texture.addToCache(texture, i);
        textures[i] = texture;
        frameIndex++;
    }
    return textures;
}
/**
 * 加载sht图集
 * @param url
 * @param onSuccess
 * @param onFail
 * @param imgUrl
 */
function loadSheet(url, onSuccess, onFail, imgUrl) {
    //替换后缀改成.png
    imgUrl = imgUrl || url.substring(0, url.lastIndexOf('.')) + '.png';
    //用promise的写法吧，方便
    Promise.all([
        //数据
        new Promise(function (r) {
            loadJson(url, r, function () { return r(null); });
        }),
        //图片
        new Promise(function (r) {
            loadImage(imgUrl, function (image) { return r(BaseTexture.fromImage(image)); }, function () { return r(null); });
        })
    ]).then(function (results) {
        if (results[0] && results[1]) {
            var textures = createTextureSheet(results[1], results[0]);
            onSuccess && onSuccess(textures);
        }
        else {
            onFail && onFail("load failed for sht:" + url);
        }
    });
}

var Tween = /** @class */ (function () {
    /**
     * 创建一个 Tween 对象
     * @private
     * @version
     * @platform Web,Native
     */
    function Tween(target, props, pluginData) {
        /**
         * @private
         */
        this._target = null;
        /**
         * @private
         */
        this._useTicks = false;
        /**
         * @private
         */
        this.ignoreGlobalPause = false;
        /**
         * @private
         */
        this.loop = false;
        /**
         * @private
         */
        this.pluginData = null;
        /**
         * @private
         */
        this._steps = null;
        /**
         * @private
         */
        this.paused = false;
        /**
         * @private
         */
        this.duration = 0;
        /**
         * @private
         */
        this._prevPos = -1;
        /**
         * @private
         */
        this.position = null;
        /**
         * @private
         */
        this._prevPosition = 0;
        /**
         * @private
         */
        this._stepPosition = 0;
        /**
         * @private
         */
        this.passive = false;
        // super();
        this.initialize(target, props, pluginData);
    }
    /**
     * Activate an object and add a Tween animation to the object
     * @param target {any} The object to be activated
     * @param props {any} Parameters, support loop onChange onChangeObj
     * @param pluginData {any} Write realized
     * @param override {boolean} Whether to remove the object before adding a tween, the default value false
     * Not recommended, you can use Tween.removeTweens(target) instead.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * 激活一个对象，对其添加 Tween 动画
     * @param target {any} 要激活 Tween 的对象
     * @param props {any} 参数，支持loop(循环播放) onChange(变化函数) onChangeObj(变化函数作用域)
     * @param pluginData {any} 暂未实现
     * @param override {boolean} 是否移除对象之前添加的tween，默认值false。
     * 不建议使用，可使用 Tween.removeTweens(target) 代替。
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Tween.get = function (target, props, pluginData, override) {
        if (pluginData === void 0) { pluginData = null; }
        if (override === void 0) { override = false; }
        if (override) {
            Tween.removeTweens(target);
        }
        return new Tween(target, props, pluginData);
    };
    /**
     * Delete all Tween animations from an object
     * @param target The object whose Tween to be deleted
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * 删除一个对象上的全部 Tween 动画
     * @param target  需要移除 Tween 的对象
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Tween.removeTweens = function (target) {
        if (!target.tween_count) {
            return;
        }
        var tweens = Tween._tweens;
        for (var i = tweens.length - 1; i >= 0; i--) {
            if (tweens[i]._target == target) {
                tweens[i].paused = true;
                tweens.splice(i, 1);
            }
        }
        target.tween_count = 0;
    };
    /**
     * 移除tween
     * @param tween get返回的Tween实例
     */
    Tween.removeTweenSelf = function (tween) {
        if (!tween || !tween._target || !tween._target.tween_count)
            return;
        tween.paused = true;
        var tweens = Tween._tweens;
        var index = tweens.indexOf(tween);
        if (index > -1)
            tweens.splice(index, 1);
        tween._target.tween_count--;
    };
    /**
     * Pause all Tween animations of a certain object
     * @param target The object whose Tween to be paused
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * 暂停某个对象的所有 Tween
     * @param target 要暂停 Tween 的对象
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Tween.pauseTweens = function (target) {
        if (!target.tween_count) {
            return;
        }
        var tweens = Tween._tweens;
        for (var i = tweens.length - 1; i >= 0; i--) {
            if (tweens[i]._target == target) {
                tweens[i].paused = true;
            }
        }
    };
    /**
     * Resume playing all easing of a certain object
     * @param target The object whose Tween to be resumed
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * 继续播放某个对象的所有缓动
     * @param target 要继续播放 Tween 的对象
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Tween.resumeTweens = function (target) {
        if (!target.tween_count) {
            return;
        }
        var tweens = Tween._tweens;
        for (var i = tweens.length - 1; i >= 0; i--) {
            if (tweens[i]._target == target) {
                tweens[i].paused = false;
            }
        }
    };
    /**
     * @private
     *
     * @param delta
     * @param paused
     */
    Tween.tick = function (timeStamp, paused) {
        if (paused === void 0) { paused = false; }
        var delta = timeStamp - Tween._lastTime;
        Tween._lastTime = timeStamp;
        var tweens = Tween._tweens.concat();
        for (var i = tweens.length - 1; i >= 0; i--) {
            var tween = tweens[i];
            if ((paused && !tween.ignoreGlobalPause) || tween.paused) {
                continue;
            }
            tween.$tick(tween._useTicks ? 1 : delta);
        }
        return false;
    };
    /**
     * flush方法，为了能加入总循环
     * 默认是锁步的
     * @param delta
     * @param paused ,暂时不用，全局禁止
     */
    Tween.flush = function ( /*paused = false*/) {
        var timeStamp = Date.now();
        var delta = Tween._lastTime ? (timeStamp - Tween._lastTime) : 16.67;
        Tween._lastTime = timeStamp;
        var tweens = Tween._tweens.concat();
        for (var i = tweens.length - 1; i >= 0; i--) {
            var tween = tweens[i];
            if ( /*(paused && !tween.ignoreGlobalPause) ||*/tween.paused) {
                continue;
            }
            tween.$tick(tween._useTicks ? 1 : delta);
        }
    };
    /**
     * @private
     *
     * @param tween
     * @param value
     */
    Tween._register = function (tween, value) {
        var target = tween._target;
        var tweens = Tween._tweens;
        if (value) {
            if (target) {
                target.tween_count = target.tween_count > 0 ? target.tween_count + 1 : 1;
            }
            tweens.push(tween);
            if (!Tween._inited) {
                // Tween._lastTime = Date.now();
                //开始加入循环暂时从简,最后实际使用，最好加入Stage总循环中
                // let aaa = () => {
                //     Tween.tick(Date.now())
                //     requestAnimationFrame(aaa)
                // }
                //必须做延时
                // setTimeout(aaa, 16.7)
                // aaa();
                // ticker.$startTick(Tween.tick, null);
                Tween._inited = true;
            }
        }
        else {
            if (target) {
                target.tween_count--;
            }
            var i = tweens.length;
            while (i--) {
                if (tweens[i] == tween) {
                    tweens.splice(i, 1);
                    return;
                }
            }
        }
    };
    /**
     * Delete all Tween
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * 删除所有 Tween
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Tween.removeAllTweens = function () {
        var tweens = Tween._tweens;
        for (var i = 0, l = tweens.length; i < l; i++) {
            var tween = tweens[i];
            tween.paused = true;
            tween._target.tween_count = 0;
        }
        tweens.length = 0;
    };
    /**
     * @private
     *
     * @param target
     * @param props
     * @param pluginData
     */
    Tween.prototype.initialize = function (target, props, pluginData) {
        this._target = target;
        if (props) {
            this._useTicks = props.useTicks;
            this.ignoreGlobalPause = props.ignoreGlobalPause;
            this.loop = props.loop;
            if (props.onChange) {
                this.onChange = props.onChange.bind(props.onChangeObj);
            }
            else {
                this.onChange = null;
            }
            // && this.addEventListener("change", props.onChange.bind(props.onChangeObj));
            if (props.override) {
                Tween.removeTweens(target);
            }
        }
        this.pluginData = pluginData || {};
        this._curQueueProps = {};
        this._initQueueProps = {};
        this._steps = [];
        if (props && props.paused) {
            this.paused = true;
        }
        else {
            Tween._register(this, true);
        }
        if (props && props.position != null) {
            this.setPosition(props.position, Tween.NONE);
        }
    };
    /**
     * @private
     *
     * @param value
     * @param actionsMode
     * @returns
     */
    Tween.prototype.setPosition = function (value, actionsMode) {
        if (actionsMode === void 0) { actionsMode = 1; }
        if (value < 0) {
            value = 0;
        }
        //正常化位置
        var t = value;
        var end = false;
        if (t >= this.duration) {
            if (this.loop) {
                var newTime = t % this.duration;
                if (t > 0 && newTime === 0) {
                    t = this.duration;
                }
                else {
                    t = newTime;
                }
            }
            else {
                t = this.duration;
                end = true;
            }
        }
        if (t == this._prevPos) {
            return end;
        }
        if (end) {
            this.setPaused(true);
        }
        var prevPos = this._prevPos;
        this.position = this._prevPos = t;
        this._prevPosition = value;
        if (this._target) {
            if (this._steps.length > 0) {
                // 找到新的tween
                var l = this._steps.length;
                var stepIndex = -1;
                for (var i = 0; i < l; i++) {
                    if (this._steps[i].type == "step") {
                        stepIndex = i;
                        if (this._steps[i].t <= t && this._steps[i].t + this._steps[i].d >= t) {
                            break;
                        }
                    }
                }
                for (var i = 0; i < l; i++) {
                    if (this._steps[i].type == "action") {
                        //执行actions
                        if (actionsMode != 0) {
                            if (this._useTicks) {
                                this._runAction(this._steps[i], t, t);
                            }
                            else if (actionsMode == 1 && t < prevPos) {
                                if (prevPos != this.duration) {
                                    this._runAction(this._steps[i], prevPos, this.duration);
                                }
                                this._runAction(this._steps[i], 0, t, true);
                            }
                            else {
                                this._runAction(this._steps[i], prevPos, t);
                            }
                        }
                    }
                    else if (this._steps[i].type == "step") {
                        if (stepIndex == i) {
                            var step = this._steps[stepIndex];
                            this._updateTargetProps(step, Math.min((this._stepPosition = t - step.t) / step.d, 1));
                        }
                    }
                }
            }
        }
        this.onChange && this.onChange();
        // this.dispatchEvent("change");
        return end;
    };
    /**
     * @private
     *
     * @param startPos
     * @param endPos
     * @param includeStart
     */
    Tween.prototype._runAction = function (action, startPos, endPos, includeStart) {
        if (includeStart === void 0) { includeStart = false; }
        var sPos = startPos;
        var ePos = endPos;
        if (startPos > endPos) {
            //把所有的倒置
            sPos = endPos;
            ePos = startPos;
        }
        var pos = action.t;
        if (pos == ePos || (pos > sPos && pos < ePos) || (includeStart && pos == startPos)) {
            action.f.apply(action.o, action.p);
        }
    };
    /**
     * @private
     *
     * @param step
     * @param ratio
     */
    Tween.prototype._updateTargetProps = function (step, ratio) {
        var p0, p1, v, v0, v1, arr;
        if (!step && ratio == 1) {
            this.passive = false;
            p0 = p1 = this._curQueueProps;
        }
        else {
            this.passive = !!step.v;
            //不更新props.
            if (this.passive) {
                return;
            }
            //使用ease
            if (step.e) {
                ratio = step.e(ratio, 0, 1, 1);
            }
            p0 = step.p0;
            p1 = step.p1;
        }
        for (var n in this._initQueueProps) {
            if ((v0 = p0[n]) == null) {
                p0[n] = v0 = this._initQueueProps[n];
            }
            if ((v1 = p1[n]) == null) {
                p1[n] = v1 = v0;
            }
            if (v0 == v1 || ratio == 0 || ratio == 1 || (typeof (v0) != "number")) {
                v = ratio == 1 ? v1 : v0;
            }
            else {
                v = v0 + (v1 - v0) * ratio;
            }
            var ignore = false;
            if (arr = Tween._plugins[n]) {
                for (var i = 0, l = arr.length; i < l; i++) {
                    var v2 = arr[i].tween(this, n, v, p0, p1, ratio, !!step && p0 == p1, !step);
                    if (v2 == Tween.IGNORE) {
                        ignore = true;
                    }
                    else {
                        v = v2;
                    }
                }
            }
            if (!ignore) {
                this._target[n] = v;
            }
        }
    };
    /**
     * Whether setting is paused
     * @param value {boolean} Whether to pause
     * @returns Tween object itself
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * 设置是否暂停
     * @param value {boolean} 是否暂停
     * @returns Tween对象本身
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Tween.prototype.setPaused = function (value) {
        if (this.paused == value) {
            return this;
        }
        this.paused = value;
        Tween._register(this, !value);
        return this;
    };
    /**
     * @private
     *
     * @param props
     * @returns
     */
    Tween.prototype._cloneProps = function (props) {
        var o = {};
        for (var n in props) {
            o[n] = props[n];
        }
        return o;
    };
    /**
     * @private
     *
     * @param o
     * @returns
     */
    Tween.prototype._addStep = function (o) {
        if (o.d > 0) {
            o.type = "step";
            this._steps.push(o);
            o.t = this.duration;
            this.duration += o.d;
        }
        return this;
    };
    /**
     * @private
     *
     * @param o
     * @returns
     */
    Tween.prototype._appendQueueProps = function (o) {
        var arr, oldValue, i, l, injectProps;
        for (var n in o) {
            if (this._initQueueProps[n] === undefined) {
                oldValue = this._target[n];
                //设置plugins
                if (arr = Tween._plugins[n]) {
                    for (i = 0, l = arr.length; i < l; i++) {
                        oldValue = arr[i].init(this, n, oldValue);
                    }
                }
                this._initQueueProps[n] = this._curQueueProps[n] = (oldValue === undefined) ? null : oldValue;
            }
            else {
                oldValue = this._curQueueProps[n];
            }
        }
        for (var n in o) {
            oldValue = this._curQueueProps[n];
            if (arr = Tween._plugins[n]) {
                injectProps = injectProps || {};
                for (i = 0, l = arr.length; i < l; i++) {
                    if (arr[i].step) {
                        arr[i].step(this, n, oldValue, o[n], injectProps);
                    }
                }
            }
            this._curQueueProps[n] = o[n];
        }
        if (injectProps) {
            this._appendQueueProps(injectProps);
        }
        return this._curQueueProps;
    };
    /**
     * @private
     *
     * @param o
     * @returns
     */
    Tween.prototype._addAction = function (o) {
        o.t = this.duration;
        o.type = "action";
        this._steps.push(o);
        return this;
    };
    /**
     * @private
     *
     * @param props
     * @param o
     */
    Tween.prototype._set = function (props, o) {
        for (var n in props) {
            o[n] = props[n];
        }
    };
    /**
     * Wait the specified milliseconds before the execution of the next animation
     * @param duration {number} Waiting time, in milliseconds
     * @param passive {boolean} Whether properties are updated during the waiting time
     * @returns Tween object itself
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * 等待指定毫秒后执行下一个动画
     * @param duration {number} 要等待的时间，以毫秒为单位
     * @param passive {boolean} 等待期间属性是否会更新
     * @returns Tween对象本身
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Tween.prototype.wait = function (duration, passive) {
        if (duration == null || duration <= 0) {
            return this;
        }
        var o = this._cloneProps(this._curQueueProps);
        return this._addStep({ d: duration, p0: o, p1: o, v: passive });
    };
    /**
     * Modify the property of the specified object to a specified value
     * @param props {Object} Property set of an object
     * @param duration {number} Duration
     * @param ease {Ease} Easing algorithm
     * @returns {Tween} Tween object itself
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * 将指定对象的属性修改为指定值
     * @param props {Object} 对象的属性集合
     * @param duration {number} 持续时间
     * @param ease {Ease} 缓动算法
     * @returns {Tween} Tween对象本身
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Tween.prototype.to = function (props, duration, ease) {
        if (ease === void 0) { ease = undefined; }
        if (isNaN(duration) || duration < 0) {
            duration = 0;
        }
        this._addStep({ d: duration || 0, p0: this._cloneProps(this._curQueueProps), e: ease, p1: this._cloneProps(this._appendQueueProps(props)) });
        //加入一步set，防止游戏极其卡顿时候，to后面的call取到的属性值不对
        return this.set(props);
    };
    /**
     * by
     * @param props
     * @param duration
     * @param ease
     */
    Tween.prototype.by = function (props, duration, ease) {
        if (duration === void 0) { duration = 0; }
        if (ease === void 0) { ease = undefined; }
        for (var k in props) {
            props[k] += this._curQueueProps[k] || this._target[k];
        }
        return this.to(props, duration, ease);
    };
    /**
     * Execute callback function
     * @param callback {Function} Callback method
     * @param thisObj {any} this action scope of the callback method
     * @param params {any[]} Parameter of the callback method
     * @returns {Tween} Tween object itself
     * @version
     * @platform Web,Native
     * @example
     * <pre>
     *  Tween.get(display).call(function (a:number, b:string) {
     *      console.log("a: " + a); // the first parameter passed 233
     *      console.log("b: " + b); // the second parameter passed “hello”
     *  }, this, [233, "hello"]);
     * </pre>
     * @language en_US
     */
    /**
     * 执行回调函数
     * @param callback {Function} 回调方法
     * @param thisObj {any} 回调方法this作用域
     * @param params {any[]} 回调方法参数
     * @returns {Tween} Tween对象本身
     * @version
     * @platform Web,Native
     * @example
     * <pre>
     *  Tween.get(display).call(function (a:number, b:string) {
     *      console.log("a: " + a); //对应传入的第一个参数 233
     *      console.log("b: " + b); //对应传入的第二个参数 “hello”
     *  }, this, [233, "hello"]);
     * </pre>
     * @language zh_CN
     */
    Tween.prototype.call = function (callback, thisObj, params) {
        if (thisObj === void 0) { thisObj = undefined; }
        if (params === void 0) { params = undefined; }
        return this._addAction({ f: callback, p: params ? params : [], o: thisObj ? thisObj : this._target });
    };
    /**
     * Now modify the properties of the specified object to the specified value
     * @param props {Object} Property set of an object
     * @param target The object whose Tween to be resumed
     * @returns {Tween} Tween object itself
     * @version
     * @platform Web,Native
     */
    /**
     * 立即将指定对象的属性修改为指定值
     * @param props {Object} 对象的属性集合
     * @param target 要继续播放 Tween 的对象
     * @returns {Tween} Tween对象本身
     * @version
     * @platform Web,Native
     */
    Tween.prototype.set = function (props, target) {
        if (target === void 0) { target = null; }
        //更新当前数据，保证缓动流畅性
        this._appendQueueProps(props);
        // console.log(this._target.x)
        return this._addAction({ f: this._set, o: this, p: [props, target ? target : this._target] });
    };
    /**
     * Execute
     * @param tween {Tween} The Tween object to be operated. Default: this
     * @returns {Tween} Tween object itself
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * 执行
     * @param tween {Tween} 需要操作的 Tween 对象，默认this
     * @returns {Tween} Tween对象本身
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Tween.prototype.play = function (tween) {
        if (!tween) {
            tween = this;
        }
        return this.call(tween.setPaused, tween, [false]);
    };
    /**
     * Pause
     * @param tween {Tween} The Tween object to be operated. Default: this
     * @returns {Tween} Tween object itself
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * 暂停
     * @param tween {Tween} 需要操作的 Tween 对象，默认this
     * @returns {Tween} Tween对象本身
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Tween.prototype.pause = function (tween) {
        if (!tween) {
            tween = this;
        }
        return this.call(tween.setPaused, tween, [true]);
    };
    /**
     * @method Tween#tick
     * @param delta {number}
     * @private
     * @version
     * @platform Web,Native
     */
    Tween.prototype.$tick = function (delta) {
        if (this.paused) {
            return;
        }
        this.setPosition(this._prevPosition + delta);
    };
    /**
     * 不做特殊处理
     * @constant {number} Tween.NONE
     * @private
     */
    Tween.NONE = 0;
    /**
     * 循环
     * @constant {number} Tween.LOOP
     * @private
     */
    Tween.LOOP = 1;
    /**
     * 倒序
     * @constant {number} Tween.REVERSE
     * @private
     */
    Tween.REVERSE = 2;
    /**
     * @private
     */
    Tween._tweens = [];
    /**
     * @private
     */
    Tween.IGNORE = {};
    /**
     * @private
     */
    Tween._plugins = {};
    /**
     * @private
     */
    Tween._inited = false;
    Tween._lastTime = 0;
    return Tween;
}());

var hasWarned;
var Button = /** @class */ (function (_super) {
    __extends(Button, _super);
    function Button(tUp, tDown, tDisable) {
        var _this = _super.call(this, tUp) || this;
        _this._clicked = false;
        if (!hasWarned)
            console.warn("Class Button will be abandoned later,maybe you can:\nfunction addClickZoom(dis: DisplayObject, zoomCenter: boolean = true) {\n    if (zoomCenter) {\n        dis.anchorX = dis.width / 2;\n        dis.anchorY = dis.height / 2;\n    }\n    dis.addEventListener(\"onMouseDown\", _mouseEvent, dis)\n        .addEventListener(\"onMouseUp\", _mouseEvent, dis)\n        .addEventListener(\"onMouseOut\", _mouseEvent, dis);\n    let s = dis;\n    function _mouseEvent(e: MouseEvent) {\n        if (e.type == MouseEvent.MOUSE_DOWN) {\n            Tween.removeTweens(s);\n            Tween.get(s).to({ scaleX: 0.9, scaleY: 0.9 }, 50);\n        } else {\n            Tween.removeTweens(s);\n            Tween.get(s).to({ scaleX: 1, scaleY: 1 }, 50);\n        }\n    }\n}");
        hasWarned = true;
        _this._instanceType = "Button";
        _this.textureUp = tUp;
        _this.textureDown = tDown === tUp ? null : tDown;
        _this.textureDisable = tDisable || tUp;
        //直接设置纹理的中心点为锚点，传入有纹理才设置，以防止报错
        if (_this.textureUp) {
            _this.anchorX = _this.textureUp.width / 2;
            _this.anchorY = _this.textureUp.height / 2;
        }
        _this.initButton();
        return _this;
    }
    /**
     * 修改纹理
     * @param tUp
     * @param tDown
     * @param tDisable
     */
    Button.prototype.changeTexture = function (tUp, tDown, tDisable) {
        this.textureUp = tUp;
        this.textureDown = tDown === tUp ? null : tDown;
        this.textureDisable = tDisable || tUp;
        if (this.textureUp) { //传入有纹理才设置，以防止报错
            this.anchorX = this.textureUp.width / 2;
            this.anchorY = this.textureUp.height / 2;
        }
        //如果是点击状态时且有down
        if (this._clicked && this.textureDown) {
            this.texture = this.textureDown;
        }
        //禁用状态时
        else if (!this.mouseEnable && !this.textureStatusEnable) {
            this.texture = this.textureDisable;
        }
        else {
            this.texture = this.textureUp;
        }
    };
    /**
     * @method  _mouseEvent
     * @param e
     * @private
     */
    Button.prototype._mouseEvent = function (e) {
        var s = this;
        if (!s._clicked) {
            if (e.type == MouseEvent.MOUSE_DOWN) {
                //如果是点下
                if (s.textureDown) {
                    s.texture = s.textureDown;
                }
                else {
                    this["frames"] = null;
                    // s.scale.x = s.scale.y = 0.9
                    Tween.removeTweens(this);
                    Tween.get(this).to({ scaleX: 0.9, scaleY: 0.9 }, 50);
                }
            }
            else {
                if (s.textureDown) {
                    s.texture = s.textureUp;
                }
                else {
                    this["frames"] = this["framesOri"];
                    // s.scale.x = s.scale.y = 1
                    Tween.removeTweens(this);
                    Tween.get(this).to({ scaleX: 1, scaleY: 1 }, 50);
                }
            }
        }
    };
    Button.prototype.initButton = function () {
        var s = this;
        s.mouseChildren = false;
        s.addEventListener("onMouseDown", s._mouseEvent, s);
        s.addEventListener("onMouseUp", s._mouseEvent, s);
        s.addEventListener("onMouseOut", s._mouseEvent, s);
        s.texture = s.textureUp;
    };
    Object.defineProperty(Button.prototype, "clicked", {
        get: function () {
            return this._clicked;
        },
        /**
         * 设置是否为点击状态
         * @property clicked
         * @param {boolean} value
         * @public
         * @since 2.0.0
         * @default false
         */
        set: function (value) {
            var s = this;
            if (value != s._clicked) {
                if (value) {
                    s._mouseEvent({ type: "onMouseDown" });
                }
                s._clicked = value;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Button.prototype, "textureStatusEnable", {
        //设置texture状态textureUp和textureDisable
        set: function (value) {
            if (value) {
                this.texture = this.textureUp;
            }
            else {
                if (this.textureDisable) {
                    this.texture = this.textureDisable;
                    this["frames"] = null;
                }
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Button.prototype, "enabled", {
        set: function (value) {
            this.mouseEnable = value;
            this.textureStatusEnable = value;
        },
        enumerable: false,
        configurable: true
    });
    Button.prototype.destroy = function () {
        this.textureUp = null;
        this.textureDown = null;
        this.textureDisable = null;
        Tween.removeTweens(this);
        _super.prototype.destroy.call(this);
    };
    return Button;
}(Sprite));

/**
 * 抽象动画类，暂时用于SvgaAni和Lottie的基类
 */
var AnimationNode = /** @class */ (function (_super) {
    __extends(AnimationNode, _super);
    function AnimationNode(data) {
        var _this = _super.call(this) || this;
        _this._instanceType = "AnimationNode";
        _this.init(data);
        return _this;
    }
    Object.defineProperty(AnimationNode.prototype, "width", {
        /**
         * 重写Container父类
         * 获取videoWidth的宽度和缩放乘积
         * @member {number}
         */
        get: function () {
            return Math.abs(this.scale.x) * this.videoWidth;
        },
        /**
         * 重写父级
         * 根据videoWidth设置自身缩放x到设置的数值
         */
        set: function (value) {
            var s = sign(this.scale.x) || 1;
            this.scale.x = s * value / this.videoWidth;
            this._width = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(AnimationNode.prototype, "height", {
        /**
         * 获取videoHeight的高度和缩放乘积
         * @member {number}
         */
        get: function () {
            return Math.abs(this.scale.y) * this.videoHeight;
        },
        /**
         * 根据videoHeight设置自身缩放y到设置的数值
         */
        set: function (value) {
            var s = sign(this.scale.y) || 1;
            this.scale.y = s * value / this.videoHeight;
            this._height = value;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 数据更新时触发，对原先设置过宽高的需要额外处理，一般在init里面自动就行
     */
    AnimationNode.prototype._onRawDataUpdate = function () {
        if (this._width) {
            this.width = this._width;
            // this.scale.x = sign(this.scale.x) * this._width / this.videoWidth;
        }
        if (this._height) {
            this.height = this._height;
            // this.scale.y = sign(this.scale.y) * this._height / this.videoHeight;
        }
    };
    /**
     * 更新方法，直接写了，后续继承的Lottie和SvgaAni基本不用改，有需要自行重写
     */
    AnimationNode.prototype.update = function () {
        if (this.animationClip) {
            var now = Date.now();
            var delta = this.lastTime ? (now - this.lastTime) * 0.001 : 0.01667;
            this.lastTime = now;
            //时间需要转换下帧小数，animationClip及各个track里的都是帧数
            this.animationClip.update(delta * this.fps);
        }
        _super.prototype.update.call(this);
    };
    /**
     * 从头播放，需要自定义的用this.animationClip
     * @param {number|boolean} loop 播放测试，默认0，一直循环播放
     * @param callback 回调
     */
    AnimationNode.prototype.play = function (loop, callback, isFront) {
        if (isFront === void 0) { isFront = true; }
        if (!this.animationClip)
            return;
        //如果没有参数，或者第一个参数是布尔的走animationClip.play
        if (!arguments.length || typeof arguments[0] == "boolean") {
            this.animationClip.play(arguments[0]);
            return;
        }
        //其他走播放次数
        loop = loop || 0;
        var endTime = this.animationClip.totalTime; //其实就是this.totalFrames
        this.animationClip.startAniRange(isFront ? 0 : endTime, isFront ? endTime : 0, loop, callback);
    };
    /**
     * 停止，需要自定义的用this.animationClip
     * @param isReset 是否重置，默认false，不重置
     */
    AnimationNode.prototype.stop = function (isReset) {
        if (isReset === void 0) { isReset = false; }
        if (!this.animationClip)
            return;
        isReset ? this.animationClip.gotoAndStop(0, true) : this.animationClip.stop();
    };
    Object.defineProperty(AnimationNode.prototype, "currentFrame", {
        /**
         * 当前帧，从0开始
         * @property currentFrame
         * @public
         * @since 1.0.0
         * @type {number}
         * @default 1
         * @readonly
         */
        get: function () {
            return this.animationClip ? Math.round(this.animationClip.currentTime) : 0;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(AnimationNode.prototype, "isPlaying", {
        /**
         * 当前动画是否处于播放状态
         * @property isPlaying
         * @readOnly
         * @public
         * @since 1.0.0
         * @type {boolean}
         * @default true
         * @readonly
         */
        get: function () {
            return this.animationClip ? this.animationClip.isPlaying : false;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(AnimationNode.prototype, "isFront", {
        /**
         * 动画的播放方向,是顺着播还是在倒着播
         * @property isFront
         * @public
         * @since 1.0.0
         * @type {boolean}
         * @default true
         * @readonly
         */
        get: function () {
            return this.animationClip ? this.animationClip.isFront : true;
        },
        enumerable: false,
        configurable: true
    });
    return AnimationNode;
}(Container));
//这三个直接用clip的
["gotoAndStop", "gotoAndPlay", "startAniRange"].forEach(function (v) {
    Object.defineProperty(AnimationNode.prototype, v, {
        value: function () {
            var _a;
            if (!this.animationClip)
                return;
            //直接用
            (_a = this.animationClip)[v].apply(_a, Array.prototype.slice.call(arguments));
        },
        writable: true,
        enumerable: true,
    });
});

/**
 * 不需要挂到节点上
 * 暂时没有帧，只有时间，以后再说
 * 用update更新
 * 通用的动画类，track自定义
 */
var AnimationClip = /** @class */ (function (_super) {
    __extends(AnimationClip, _super);
    /**
     *
     * @param tracks
     * @param totalTime 总时间自行传入，秒计，
     */
    function AnimationClip(tracks, totalTime) {
        var _this = _super.call(this) || this;
        _this._isPlaying = true;
        _this._isFront = true;
        /**
         * 上个时间，用来确定是否更新
         */
        _this.lastTime = null;
        /**
         * 记录时间
         */
        _this.curTime = 0;
        _this._endMark = false;
        _this._instanceType = "AnimationClip";
        _this.tracks = tracks;
        _this._totalTime = totalTime;
        return _this;
    }
    Object.defineProperty(AnimationClip.prototype, "totalTime", {
        /**
         * 动画总时长，一般是所有tracks里时间最长的那个
         * @readonly
         */
        get: function () {
            return this._totalTime;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 初始化方法
     * @param tracks
     * @param totalTime
     */
    AnimationClip.prototype.init = function (tracks, totalTime) {
        this.tracks = tracks;
        this._totalTime = totalTime;
        //事件移除，其实帧数完全一致的话，不会出问题，一样能触发回调
        if (this.startAniRangeFun)
            this.removeEventListener(Event.ENTER_FRAME, this.startAniRangeFun, this);
        //下面这些暂时不考虑初始化，MovieClip暂时也没有，估计静止的时候都会出问题
        // this._isPlaying = true;
        // this._isFront = true;
        // this.lastTime = null;
        // this.curTime = 0;
        // this._endMark = false;
    };
    Object.defineProperty(AnimationClip.prototype, "isPlaying", {
        /**
         * 是否播放中
         * @readonly
         */
        get: function () {
            return this._isPlaying;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(AnimationClip.prototype, "isFront", {
        /**
         * 是否正向播放
         * @readonly
         */
        get: function () {
            return this._isFront;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(AnimationClip.prototype, "currentTime", {
        /**
         * 当前时间
         */
        get: function () {
            return this.curTime;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 需要挂在循环里的方法，传时间间隔
     * @param time 一般为秒计
     */
    AnimationClip.prototype.update = function (time) {
        if (!this.tracks || !this.tracks.length)
            return;
        //时间不等，直接播放
        if (this.curTime !== this.lastTime) {
            this.rectify();
            this._endMark = false;
            return;
        }
        //时间没有，或没在播放
        if (time <= 0 || !this._isPlaying)
            return;
        this._endMark = false;
        if (this._isFront) {
            this.curTime += time;
            if (this.curTime > this._totalTime) {
                this.curTime = 0;
                this._endMark = true;
            }
        }
        else {
            this.curTime -= time;
            if (this.curTime < 0) {
                this.curTime = this._totalTime;
                this._endMark = true;
            }
        }
        if (this.curTime !== this.lastTime) {
            //矫正
            this.rectify();
            //派发每帧事件
            this.dispatchEvent(Event.ENTER_FRAME);
            //派发结束帧事件
            if (this._endMark && this.hasEventListener(Event.END_FRAME)) {
                this.dispatchEvent(Event.END_FRAME);
            }
        }
    };
    /**
     * 从当前时间点播放
     * @param isFront 默认true正向
     */
    AnimationClip.prototype.play = function (isFront) {
        if (isFront === void 0) { isFront = true; }
        this._isFront = isFront;
        this._isPlaying = true;
    };
    /**
     * 停在当前时间
     */
    AnimationClip.prototype.stop = function () {
        this._isPlaying = false;
        this.lastTime = this.curTime;
    };
    /**
     * 从某时刻开始播放
     * @param time
     * @param isFront 默认true，正向播放
     */
    AnimationClip.prototype.gotoAndPlay = function (time, isFront) {
        if (isFront === void 0) { isFront = true; }
        var s = this;
        s._isFront = isFront;
        s._isPlaying = true;
        // if (time > s._totalTime) time = s._totalTime;
        // if (time < 0) time = 0;
        time = clamp(time, 0, s._totalTime); //改成用clamp
        s.curTime = time;
    };
    /**
     * 停在指定时间
     * @param time
     * @param force 是否强制更新，默认false，如果发现没stop在指定位置，可以试试设置true
     */
    AnimationClip.prototype.gotoAndStop = function (time, force) {
        if (force === void 0) { force = false; }
        this._isPlaying = false;
        // if (time > this.totalTime) time = this.totalTime;
        // if (time < 0) time = 0;
        time = clamp(time, 0, this._totalTime); //改成用clamp
        this.curTime = time;
        //这样会强制更新
        if (force)
            this.lastTime = null;
    };
    /**
     * 在一个区间范围内播放
     * @param beginTime 开始时间，秒计，默认0，
     * @param endTime 结束时间，秒计，默认_totalTime
     * @param loops 循环次数，0或负数表示无限循环，默认1
     * @param callback 播放完成后的回调，无限循环时无效
     */
    AnimationClip.prototype.startAniRange = function (beginTime, endTime, loops, callback) {
        if (beginTime === void 0) { beginTime = 0; }
        if (endTime === void 0) { endTime = this._totalTime; }
        if (loops === void 0) { loops = 1; }
        //loops处理下
        loops = loops || 0; //去掉null等等
        loops = Math.max(0, loops); //去掉负数
        // if (beginTime <= 0) beginTime = 0;
        // if (beginTime > this._totalTime) beginTime = this._totalTime;
        // if (endTime <= 0) endTime = 0;
        // if (endTime > this._totalTime) endTime = this._totalTime;
        beginTime = clamp(beginTime, 0, this._totalTime);
        endTime = clamp(endTime, 0, this._totalTime);
        if (beginTime === endTime) {
            this.gotoAndStop(beginTime);
            //如果相等
            return;
        }
        else {
            this._isFront = beginTime < endTime;
        }
        //移除原先的绑定吧
        if (this.startAniRangeFun)
            this.removeEventListener(Event.ENTER_FRAME, this.startAniRangeFun, this);
        this.curTime = beginTime;
        this._isPlaying = true;
        var loopCount = loops ? (loops + 0.5 >> 0) : Infinity;
        this.addEventListener(Event.ENTER_FRAME, this.startAniRangeFun = function (e) {
            var s = e.target;
            var cond = s._isFront ? s.curTime >= endTime : s.curTime <= endTime;
            if (cond || s._endMark) {
                loopCount--;
                if (loopCount <= 0) {
                    s._isPlaying = false;
                    s.curTime = endTime; //这个在下一帧才生效，所以加一个矫正rectify
                    // s.rectify();
                    s.removeEventListener(Event.ENTER_FRAME, s.startAniRangeFun, s);
                    s.startAniRangeFun = null;
                    callback && callback();
                    s.rectify(); //放在最后吧，callback里也可能干了啥
                }
                else {
                    s.curTime = beginTime;
                }
            }
        }, this);
    };
    /**
     * 矫正
     */
    AnimationClip.prototype.rectify = function () {
        if (!this.tracks || !this.tracks.length)
            return;
        for (var i = 0; i < this.tracks.length; i++) {
            this.tracks[i].setValue(this.curTime);
        }
        //设置相等
        this.lastTime = this.curTime;
    };
    /**
     * 用于重置初始状态，因为每个track的0状态也不一定是初始状态
     * 所以各自track自行处理
     */
    AnimationClip.prototype.resetState = function () {
        this.stop();
        for (var i = 0; i < this.tracks.length; i++)
            this.tracks[i].resetValue();
    };
    return AnimationClip;
}(EventDispatcher));

/**
 * 帧动画
 * 图片都以素材为中心为原点
 */
var FrameAni = /** @class */ (function (_super) {
    __extends(FrameAni, _super);
    /**
     *
     * @param data 所有的纹理资源数组
     */
    function FrameAni(data) {
        var _this = _super.call(this, data) || this;
        /**
         * 每秒刷新帧数，默认30;
         */
        _this.fps = 30;
        _this._instanceType = "FrameAni";
        return _this;
    }
    /**
     * 获取当前图片帧
     */
    FrameAni.prototype.getCurrentFrame = function () {
        console.warn("method getCurrentFrame will be abandoned soon,use property currentFrame instead");
        return this.currentFrame; //this.texturesAll.indexOf(this.showImage.texture)
    };
    Object.defineProperty(FrameAni.prototype, "totalTime", {
        /**
         * 总时间，秒计
         */
        get: function () {
            return this.rawData && this.rawData.length * (1 / this.fps) || 0;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(FrameAni.prototype, "totalFrames", {
        /**
         * 总帧数
         */
        get: function () {
            return this.rawData && this.rawData.length || 0;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(FrameAni.prototype, "videoWidth", {
        /**
         * 动画显示宽度，取最大的纹理宽度
         */
        get: function () {
            if (!this.rawData || !this.rawData.length)
                return 0;
            //上面已经判断过rawData的长度，所以不多加参数0
            return Math.max.apply(Math, this.rawData.map(function (t) { return t.width; }));
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(FrameAni.prototype, "videoHeight", {
        /**
         * 动画显示高度，取最大的纹理高度
         */
        get: function () {
            if (!this.rawData || !this.rawData.length)
                return 0;
            return Math.max.apply(Math, this.rawData.map(function (t) { return t.height; }));
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(FrameAni.prototype, "frameRate", {
        get: function () {
            console.warn("method frameRate will be abandoned soon,use property fps instead");
            return this._fps;
        },
        set: function (value) {
            console.warn("method frameRate will be abandoned soon,use property fps instead");
            this._fps = value;
        },
        enumerable: false,
        configurable: true
    });
    FrameAni.prototype.init = function (data) {
        if (!data || !data.length || data == this.rawData)
            return;
        //记录源数据
        this.rawData = data;
        //可以复用，只要一个
        if (!this.showImage) {
            this.showImage = this.addChild(new Sprite());
            this.showImage.anchorTexture.set(0.5, 0.5);
        }
        //可以复用，因为只需要一个
        if (!this.frameTrack) {
            this.frameTrack = new FrameTrack(this.showImage, data);
        }
        else {
            this.frameTrack.textures = data;
        }
        this.frameTrack.resetValue();
        //
        var tracks = [this.frameTrack];
        //合成所有时间轴，总时间按总帧数传，其实可能应该用this.totalFrames-1的，无所谓了，只是最后一帧停留了一帧
        if (!this.animationClip) {
            this.animationClip = new AnimationClip(tracks, this.totalFrames);
        }
        else {
            this.animationClip.init(tracks, this.totalFrames);
        }
        //数据更新
        this._onRawDataUpdate();
    };
    /**
     * 重置为frame，不播放，即将废弃，用gotoAndStop代替
     */
    FrameAni.prototype.reset = function (frame) {
        if (frame === void 0) { frame = 0; }
        console.warn("method reset will be abandoned soon,use method gotoAndStop instead");
        this.gotoAndStop(frame);
    };
    /**
     * 重置所有贴图，即将废弃，用init代替
     * @param texturesAll
     */
    FrameAni.prototype.resetTexturesAll = function (texturesAll) {
        console.warn("method resetTexturesAll will be abandoned soon,use method init instead");
        this.init(texturesAll);
    };
    return FrameAni;
}(AnimationNode));
var FrameTrack = /** @class */ (function (_super) {
    __extends(FrameTrack, _super);
    function FrameTrack(sprite, textures) {
        var _this = _super.call(this) || this;
        _this.sprite = sprite;
        _this.textures = textures;
        _this._instanceType = "FrameTrack";
        return _this;
    }
    /**
     * 这里用的帧数
     * @param time 帧小数
     */
    FrameTrack.prototype.setValue = function (time) {
        //处理time
        time = Math.round(clamp(time, 0, this.textures.length - 1));
        //找对应纹理
        this.sprite.texture = this.textures[time];
    };
    FrameTrack.prototype.resetValue = function () {
        this.setValue(0);
    };
    FrameTrack.prototype.destroy = function () {
        this.sprite = null;
        this.textures = null;
    };
    return FrameTrack;
}(HashObject));

var Ease = /** @class */ (function () {
    /**
     * @version
     * @platform Web,Native
     */
    function Ease() {
    }
    /**
     * get.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * get。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.get = function (amount) {
        if (amount < -1) {
            amount = -1;
        }
        if (amount > 1) {
            amount = 1;
        }
        return function (t) {
            if (amount == 0) {
                return t;
            }
            if (amount < 0) {
                return t * (t * -amount + 1 + amount);
            }
            return t * ((2 - t) * amount + (1 - amount));
        };
    };
    /**
     * get pow in.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * get pow in。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.getPowIn = function (pow) {
        return function (t) {
            return Math.pow(t, pow);
        };
    };
    /**
     * get pow out.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * get pow out。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.getPowOut = function (pow) {
        return function (t) {
            return 1 - Math.pow(1 - t, pow);
        };
    };
    /**
     * get pow in out.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * get pow in out。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.getPowInOut = function (pow) {
        return function (t) {
            if ((t *= 2) < 1)
                return 0.5 * Math.pow(t, pow);
            return 1 - 0.5 * Math.abs(Math.pow(2 - t, pow));
        };
    };
    /**
     * sine in.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * sine in。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.sineIn = function (t) {
        return 1 - Math.cos(t * Math.PI / 2);
    };
    /**
     * sine out.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * sine out。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.sineOut = function (t) {
        return Math.sin(t * Math.PI / 2);
    };
    /**
     * sine in out.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * sine in out。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.sineInOut = function (t) {
        return -0.5 * (Math.cos(Math.PI * t) - 1);
    };
    /**
     * get back in.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * get back in。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.getBackIn = function (amount) {
        return function (t) {
            return t * t * ((amount + 1) * t - amount);
        };
    };
    /**
     * get back out.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * get back out。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.getBackOut = function (amount) {
        return function (t) {
            return (--t * t * ((amount + 1) * t + amount) + 1);
        };
    };
    /**
     * get back in out.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * get back in out。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.getBackInOut = function (amount) {
        amount *= 1.525;
        return function (t) {
            if ((t *= 2) < 1)
                return 0.5 * (t * t * ((amount + 1) * t - amount));
            return 0.5 * ((t -= 2) * t * ((amount + 1) * t + amount) + 2);
        };
    };
    /**
     * circ in.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * circ in。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.circIn = function (t) {
        return -(Math.sqrt(1 - t * t) - 1);
    };
    /**
     * circ out.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * circ out。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.circOut = function (t) {
        return Math.sqrt(1 - (--t) * t);
    };
    /**
     * circ in out.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * circ in out。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.circInOut = function (t) {
        if ((t *= 2) < 1) {
            return -0.5 * (Math.sqrt(1 - t * t) - 1);
        }
        return 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1);
    };
    /**
     * bounce in.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * bounce in。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.bounceIn = function (t) {
        return 1 - Ease.bounceOut(1 - t);
    };
    /**
     * bounce out.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * bounce out。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.bounceOut = function (t) {
        if (t < 1 / 2.75) {
            return (7.5625 * t * t);
        }
        else if (t < 2 / 2.75) {
            return (7.5625 * (t -= 1.5 / 2.75) * t + 0.75);
        }
        else if (t < 2.5 / 2.75) {
            return (7.5625 * (t -= 2.25 / 2.75) * t + 0.9375);
        }
        else {
            return (7.5625 * (t -= 2.625 / 2.75) * t + 0.984375);
        }
    };
    /**
     * bounce in out.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * bounce in out。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.bounceInOut = function (t) {
        if (t < 0.5)
            return Ease.bounceIn(t * 2) * .5;
        return Ease.bounceOut(t * 2 - 1) * 0.5 + 0.5;
    };
    /**
     * get elastic in.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * get elastic in。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.getElasticIn = function (amplitude, period) {
        var pi2 = Math.PI * 2;
        return function (t) {
            if (t == 0 || t == 1)
                return t;
            var s = period / pi2 * Math.asin(1 / amplitude);
            return -(amplitude * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * pi2 / period));
        };
    };
    /**
     * get elastic out.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * get elastic out。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.getElasticOut = function (amplitude, period) {
        var pi2 = Math.PI * 2;
        return function (t) {
            if (t == 0 || t == 1)
                return t;
            var s = period / pi2 * Math.asin(1 / amplitude);
            return (amplitude * Math.pow(2, -10 * t) * Math.sin((t - s) * pi2 / period) + 1);
        };
    };
    /**
     * get elastic in out.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * get elastic in out。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.getElasticInOut = function (amplitude, period) {
        var pi2 = Math.PI * 2;
        return function (t) {
            var s = period / pi2 * Math.asin(1 / amplitude);
            if ((t *= 2) < 1)
                return -0.5 * (amplitude * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * pi2 / period));
            return amplitude * Math.pow(2, -10 * (t -= 1)) * Math.sin((t - s) * pi2 / period) * 0.5 + 1;
        };
    };
    /**
     * quad in.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * quad in。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.quadIn = Ease.getPowIn(2);
    /**
     * quad out.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * quad out。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.quadOut = Ease.getPowOut(2);
    /**
     * quad in out.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * quad in out。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.quadInOut = Ease.getPowInOut(2);
    /**
     * cubic in.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * cubic in。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.cubicIn = Ease.getPowIn(3);
    /**
     * cubic out.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * cubic out。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.cubicOut = Ease.getPowOut(3);
    /**
     * cubic in out.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * cubic in out。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.cubicInOut = Ease.getPowInOut(3);
    /**
     * quart in.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * quart in。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.quartIn = Ease.getPowIn(4);
    /**
     * quart out.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * quart out。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.quartOut = Ease.getPowOut(4);
    /**
     * quart in out.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * quart in out。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.quartInOut = Ease.getPowInOut(4);
    /**
     * quint in.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * quint in。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.quintIn = Ease.getPowIn(5);
    /**
     * quint out.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * quint out。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.quintOut = Ease.getPowOut(5);
    /**
     * quint in out.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * quint in out。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.quintInOut = Ease.getPowInOut(5);
    /**
     * back in.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * back in。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.backIn = Ease.getBackIn(1.7);
    /**
     * back out.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * back out。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.backOut = Ease.getBackOut(1.7);
    /**
     * back in out.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * back in out。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.backInOut = Ease.getBackInOut(1.7);
    /**
     * elastic in.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * elastic in。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.elasticIn = Ease.getElasticIn(1, 0.3);
    /**
     * elastic out.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * elastic out。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.elasticOut = Ease.getElasticOut(1, 0.3);
    /**
     * elastic in out.See example.
     * @version
     * @platform Web,Native
     * @language en_US
     */
    /**
     * elastic in out。请查看示例
     * @version
     * @platform Web,Native
     * @language zh_CN
     */
    Ease.elasticInOut = Ease.getElasticInOut(1, 0.3 * 1.5);
    return Ease;
}());

// import  Tween  from "../../tweenSimple/Tween";
/**
 * 滚动视图
 * @class ScrollPage
 * @public
 * @extends Container
 * @since 1.0.0
 */
var ScrollPage = /** @class */ (function (_super) {
    __extends(ScrollPage, _super);
    /**
     * 注意滚动内容在view里加
     * @method  ScrollPage
     * @param {number} vW 可视区域宽
     * @param {number} vH 可视区域高
     * @param {number} maxDistance 最大滚动的长度
     * @param {boolean} isVertical 是纵向还是横向，也就是说是滚x还是滚y,默认值为沿y方向滚动
     * @example
     *      var sPage=new ScrollPage(640,s.stage.viewRect.height,4943);
     *      sPage.isSpringBack = false;//是否回弹
     *      stage.addChild(sPage);
     *      sPage.view.addChild(view);
     *      sPage.y=stage.viewRect.y;
     *
     */
    function ScrollPage(vW, vH, maxDistance, isVertical, isFull) {
        if (isVertical === void 0) { isVertical = true; }
        if (isFull === void 0) { isFull = false; }
        var _this = _super.call(this) || this;
        /**
         * 横向还是纵向 默认为纵向
         * @property isVertical
         * @type {boolean}
         * @private
         * @since 1.0.0
         * @default true
         */
        _this.isVertical = true;
        /**
         * 可见区域的宽
         * @property viewWidth
         * @type {number}
         * @private
         * @since 1.0.0
         * @default 0
         */
        _this.viewWidth = 0;
        /**
         * 可见区域的高
         * @property viewHeight
         * @type {number}
         * @private
         * @since 1.0.0
         * @default 0
         */
        _this.viewHeight = 0;
        _this._tweenId = 0;
        /**
         * 整个滚动的最大距离值
         * @property maxDistance
         * @type {number}
         * @public
         * @since 1.0.0
         * @default 1040
         */
        _this.maxDistance = 1040;
        /**
         * @property 滚动距离
         * @type {number}
         * @protected
         * @default 0
         * @since 1.0.0
         */
        _this.distance = 0;
        /**
         * 最小鼠标滑动距离
         * @type {number}
         */
        _this.minDis = 2;
        /**
         * 遮罩对象
         * @property maskObj
         * @since 1.0.0
         * @private
         * @type {Graphics}
         */
        _this.maskObj = new Graphics();
        /**
         * 真正的容器对象，所有滚动的内容都应该是添加到这个容器中
         * @property view
         * @public
         * @since 1.0.0
         * @type {Container}
         */
        _this.view = new Container();
        /**
         * 最后鼠标经过的坐标值
         * @property lastValue
         * @private
         * @since 1.0.0
         * @type {number}
         */
        _this.lastValue = 0;
        /**
         * 速度
         * @property speed
         * @protected
         * @since 1.0.0
         * @type {number}
         */
        _this.speed = 0;
        /**
         * 加速度
         * @property addSpeed
         * @private
         * @since 1.0.0
         * @type {number}
         */
        _this.addSpeed = 0;
        /**
         * 是否是停止滚动状态
         * @property isStop
         * @public
         * @since 1.0.0
         * @type {boolean}
         * @default true
         */
        _this.isStop = true;
        /**
         * 滚动的最大速度，直接影响一次滑动之后最长可以滚多远
         * @property maxSpeed
         * @public
         * @since 1.0.0
         * @default 100
         * @type {number}
         */
        _this.maxSpeed = 100;
        /**
         * 摩擦力,值越大，减速越快
         * @property fSpeed
         * @public
         * @since 1.0.0
         * @default 20
         * @type {number}
         */
        _this.fSpeed = 20;
        _this.paramXY = "y";
        _this.stopTimes = -1;
        _this.isMouseDownState = 0;
        /**
         * 是否是通过scrollTo方法在滑动中
         * @property autoScroll
         * @since 1.0.2
         * @type {boolean}
         * @private
         * @default false
         */
        _this.autoScroll = false;
        _this.isSpringBack = true;
        console.warn("class ScrollPage will be abandoned soon, use class ScrollView instead");
        var s = _this;
        s._instanceType = "ScrollPage";
        s.addChild(s.maskObj);
        s.addChild(s.view);
        if (!isFull) {
            //不全屏才设置mask
            s.view.mask = s.maskObj;
            //为了能接收鼠标事件设置_isUsedToMask
            s.maskObj._isUsedToMask = false;
        }
        s.maskObj.alpha = 0;
        s.maxDistance = maxDistance;
        s.setViewRect(vW, vH, isVertical);
        //添加到舞台，需要注意local坐标替换成stage坐标
        s.addEventListener(Event.ADDED_TO_STAGE, function (e) {
            s.stage.addEventListener(MouseEvent.MOUSE_MOVE, s.onMouseEvent, s);
            s.stage.addEventListener(MouseEvent.MOUSE_UP, s.onMouseEvent, s);
        });
        s.addEventListener(Event.REMOVED_FROM_STAGE, function (e) {
            s.stage.removeEventListener(MouseEvent.MOUSE_MOVE, s.onMouseEvent, s);
            s.stage.removeEventListener(MouseEvent.MOUSE_UP, s.onMouseEvent, s);
        });
        s.addEventListener(MouseEvent.MOUSE_DOWN, s.onMouseEvent, s, false);
        // s.addEventListener(MouseEvent.MOUSE_MOVE, s.onMouseEvent, s);
        // s.addEventListener(MouseEvent.MOUSE_UP, s.onMouseEvent, s);
        // s.addEventListener(MouseEvent.MOUSE_OUT, s.onMouseEvent, s);
        s.addEventListener(Event.ENTER_FRAME, function () {
            var view = s.view;
            if (s.autoScroll)
                return;
            if (!s.isSpringBack) {
                if (view[s.paramXY] > 0) {
                    s.addSpeed = 0;
                    s.speed = 0;
                    s.isStop = true;
                    view[s.paramXY] = 0;
                    return;
                }
                else if (view[s.paramXY] < s.distance - s.maxDistance) {
                    s.addSpeed = 0;
                    s.speed = 0;
                    s.isStop = true;
                    view[s.paramXY] = s.distance - s.maxDistance;
                    if (s.distance > s.maxDistance)
                        view[s.paramXY] = 0;
                    return;
                }
            }
            if (!s.isStop) {
                if (Math.abs(s.speed) > 0) {
                    view[s.paramXY] += s.speed;
                    //是否超过了边界,如果超过了,则加快加速度,让其停止
                    if (view[s.paramXY] > 0 || view[s.paramXY] < s.distance - s.maxDistance) {
                        s.speed += s.addSpeed * s.fSpeed;
                    }
                    else {
                        s.speed += s.addSpeed;
                    }
                    //说明超过了界线,准备回弹
                    if (s.speed * s.addSpeed > 0) {
                        s.dispatchEvent(Event.SCROLL_STOP);
                        s.speed = 0;
                    }
                }
                else {
                    //检测是否超出了边界,如果超出了边界则回弹
                    if (s.addSpeed != 0) {
                        if (view[s.paramXY] > 0 || view[s.paramXY] < s.distance - s.maxDistance) {
                            var tarP = 0;
                            // if (s.addSpeed > 0) {
                            //     if (s.distance < s.maxDistance) {
                            //         tarP = s.distance - s.maxDistance;
                            //     }
                            // }
                            if (view[s.paramXY] < s.distance - s.maxDistance) {
                                if (s.distance < s.maxDistance) {
                                    tarP = s.distance - s.maxDistance;
                                }
                            }
                            view[s.paramXY] += 0.4 * (tarP - view[s.paramXY]);
                            if (Math.abs(tarP - view[s.paramXY]) < 0.1) {
                                s.isStop = true;
                                if (s.addSpeed > 0) {
                                    s.dispatchEvent(Event.SCROLL_TO_END);
                                }
                                else {
                                    s.dispatchEvent(Event.SCROLL_TO_HEAD);
                                }
                                s.addSpeed = 0;
                            }
                        }
                    }
                    else {
                        s.isStop = true;
                    }
                }
            }
            else {
                if (s.stopTimes >= 0) {
                    s.stopTimes++;
                    if (s.stopTimes >= 15) {
                        s.speed = 0;
                        if (view[s.paramXY] > 0 || view[s.paramXY] < s.distance - s.maxDistance) {
                            s.isStop = false;
                            s.stopTimes = -1;
                            //加一个
                            s.isMouseDownState = 0;
                        }
                    }
                }
            }
        });
        return _this;
    }
    /**
     * 设置可见区域，可见区域的坐标始终在本地坐标中0,0点位置
     * @method setViewRect
     * @param {number}w 设置可见区域的宽
     * @param {number}h 设置可见区域的高
     * @param {boolean} isVertical 方向
     * @public
     * @since 1.1.1
     */
    ScrollPage.prototype.setViewRect = function (w, h, isVertical) {
        var s = this;
        s.maskObj.clear();
        s.maskObj.beginFill("#000000");
        s.maskObj.drawRect(0, 0, w, h);
        s.viewWidth = w;
        s.viewHeight = h;
        s.maskObj.endFill();
        s.isVertical = isVertical;
        if (isVertical) {
            s.distance = s.viewHeight;
            s.paramXY = "y";
        }
        else {
            s.distance = s.viewWidth;
            s.paramXY = "x";
        }
        s.isVertical = isVertical;
    };
    ScrollPage.prototype.onMouseEvent = function (e) {
        var s = this;
        var view = s.view;
        // if (s.distance < s.maxDistance) {
        if (e.type == MouseEvent.MOUSE_DOWN) {
            e.stopPropagation();
            if (!s.isStop) {
                s.isStop = true;
            }
            if (s.autoScroll) {
                s.autoScroll = false;
                // Tween.kill(s._tweenId);
                // cancelAnimationFrame(s._tweenId)
                Tween.removeTweens(s.view);
            }
            if (s.isVertical) {
                s.lastValue = e.stageY; //e.localY;//move事件添加到舞台的，需要用stageY
            }
            else {
                s.lastValue = e.stageX; //e.localX;
            }
            s.speed = 0;
            s.isMouseDownState = 1;
        }
        else if (e.type == MouseEvent.MOUSE_MOVE) {
            if (s.isMouseDownState == 0)
                return;
            if (s.isMouseDownState == 1) {
                s.dispatchEvent(Event.SCROLL_START);
            }
            s.isMouseDownState = 2;
            var currentValue = void 0;
            if (s.isVertical) {
                currentValue = e.stageY; //e.localY;
            }
            else {
                currentValue = e.stageX; //e.localX;
            }
            s.speed = currentValue - s.lastValue;
            if (s.speed > s.minDis) {
                s.addSpeed = -2;
                if (s.speed > s.maxSpeed) {
                    s.speed = s.maxSpeed;
                }
            }
            else if (s.speed < -s.minDis) {
                if (s.speed < -s.maxSpeed) {
                    s.speed = -s.maxSpeed;
                }
                s.addSpeed = 2;
            }
            else {
                s.speed = 0;
            }
            if (s.speed != 0) {
                var speedPer = 1;
                if (view[s.paramXY] > 0 || view[s.paramXY] < s.distance - s.maxDistance) {
                    speedPer = 0.2;
                }
                view[s.paramXY] += (currentValue - s.lastValue) * speedPer;
            }
            s.lastValue = currentValue;
            s.stopTimes = 0;
        }
        else {
            if (!s.isMouseDownState)
                return; //先不加，讲道理需要，否则stage的up事件会触发这里，使得isStop改变
            s.isStop = false;
            s.stopTimes = -1;
            if (s.speed == 0 && s.isMouseDownState == 2) {
                s.dispatchEvent(Event.SCROLL_STOP);
            }
            s.isMouseDownState = 0;
        }
        // }
    };
    /**
     * 滚到指定的坐标位置
     * @method scrollTo
     * @param {number} dis 需要去到的位置,初始位置0,最大为maxDistance- s.viewWidth : s.viewHeight
     * @param {number} time 滚动需要的时间 默认为0 即没有动画效果直接跳到指定页，毫秒
     * @since 1.1.1
     * @public
     */
    ScrollPage.prototype.scrollTo = function (dis, time) {
        var _a;
        if (time === void 0) { time = 0; }
        var s = this;
        var newDis = s.paramXY == "x" ? s.viewWidth : s.viewHeight;
        if (dis < 0) {
            dis = 0;
        }
        else if (dis > s.maxDistance - newDis) {
            dis = s.maxDistance - newDis;
        }
        if (Math.abs(s.view[s.paramXY] + dis) > 2) {
            //tweenSimple版
            // s.autoScroll = true;
            // s.isStop = true;
            // s.isMouseDownState = 0;
            // let obj: any = {};
            // obj.onComplete = function () {
            //     s.autoScroll = false;
            // };
            // obj[s.paramXY] = -dis;
            // s._tweenId = Tween.to(s.view, time, obj);
            // if (s.speed == 0) {
            //     s.dispatchEvent(Event.SCROLL_START);
            // }
            //用Tween版
            s.autoScroll = true;
            s.isStop = true;
            s.isMouseDownState = 0;
            Tween.removeTweens(s.view);
            Tween.get(s.view)
                .to((_a = {}, _a[s.paramXY] = -dis, _a), time)
                .call(function () {
                s.view[s.paramXY] = -dis;
                s.autoScroll = false;
            });
            if (s.speed == 0)
                s.dispatchEvent(Event.SCROLL_START);
            //无缓动版
            // s.isStop = true;
            // s.isMouseDownState = 0;
            // s.view[s.paramXY] = -dis;
            //用计时器版
            // s.isStop = true;
            // s.isMouseDownState = 0;
            // if (time) {
            //     s.autoScroll = true;
            //     let cdis = s.view[s.paramXY];
            //     cancelAnimationFrame(s._tweenId)
            //     let last = Date.now();
            //     let fun = () => {
            //         var deltaTime = Date.now() - last;
            //         if (deltaTime > time) {
            //             s.view[s.paramXY] = -dis;
            //             s.autoScroll = false;
            //             cancelAnimationFrame(s._tweenId)
            //         } else {
            //             s.view[s.paramXY] = (-dis - cdis) * (deltaTime / time) + cdis;
            //             s._tweenId = requestAnimationFrame(fun)
            //         }
            //     }
            //     s._tweenId = requestAnimationFrame(fun)
            //     if (s.speed == 0) s.dispatchEvent(Event.SCROLL_START);
            // } else {
            //     //直接赋值
            //     s.view[s.paramXY] = -dis;
            // }
        }
    };
    ScrollPage.prototype.destroy = function () {
        //Tween去掉
        Tween.removeTweens(this.view);
        var s = this;
        s.maskObj.destroy();
        s.view.destroy();
        s.maskObj = null;
        s.view = null;
        _super.prototype.destroy.call(this);
    };
    return ScrollPage;
}(Container));

/**
 * 滚动视图
 */
var ScrollView = /** @class */ (function (_super) {
    __extends(ScrollView, _super);
    /**
     * 注意滚动内容在view里加
     * @method  ScrollPage
     * @param {number} vW 可视区域宽
     * @param {number} vH 可视区域高
     * @param {number} sW 最大横向滚动距离
     * @param {number} sH 最大纵向滚动距离
     * @param {boolean} isFullScreen 是否全屏
     * @example
     *      var scroll=new ScrollView(750,1000,0,2000);
     *      stage.addChild(scroll);
     *      //加滚动内容
     *      scroll.view.addChild(new Sprite());
     */
    function ScrollView(vW, vH, sW, sH, isFullScreen) {
        var _this = _super.call(this) || this;
        /**
         * 可见区域的宽
         * @property viewWidth
         * @type {number}
         * @protected
         * @since 1.0.0
         * @default 0
         */
        _this.viewWidth = 0;
        /**
         * 可见区域的高
         * @property viewHeight
         * @type {number}
         * @protected
         * @since 1.0.0
         * @default 0
         */
        _this.viewHeight = 0;
        _this.velocitys = [];
        /**
         * 手指拖动超过边界时是否允许回弹。默认true
         */
        _this.isBounce = true;
        /**
         * 回弹时间，视图内容在不合理的位置时恢复的时间，比如超过边界时
         */
        _this.bounceTime = 300;
        /**
         * 手指抬起后是否存在惯性。默认true
         */
        _this.hasMomentum = true;
        /**
         * 惯性的阻尼
         * 默认0.002
         */
        _this.damping = 0.002;
        /**
         * 0无交互状态
         * 1点击状态
         * 2移动状态
         */
        _this.mouseStatus = 0;
        var s = _this;
        s._instanceType = "ScrollView";
        //视图容器，必须用super.addChildAt,其他都被重写了
        s._content = _super.prototype.addChildAt.call(_this, new Container(), 0);
        s.maskObj = _super.prototype.addChildAt.call(_this, new Graphics(), 0);
        s.maskObj.alpha = 0;
        //有传过才赋值
        if (typeof sW == "number")
            s._scrollWidth = sW;
        if (typeof sH == "number")
            s._scrollHeight = sH;
        //设置第一次
        s.setViewRect(vW, vH, isFullScreen);
        //添加到舞台，需要注意local坐标替换成stage坐标
        s.addEventListener(Event.ADDED_TO_STAGE, function (e) {
            s.stage.addEventListener(MouseEvent.MOUSE_MOVE, s.onMouseEvent, s);
            s.stage.addEventListener(MouseEvent.MOUSE_UP, s.onMouseEvent, s);
        });
        s.addEventListener(Event.REMOVED_FROM_STAGE, function (e) {
            s.stage.removeEventListener(MouseEvent.MOUSE_MOVE, s.onMouseEvent, s);
            s.stage.removeEventListener(MouseEvent.MOUSE_UP, s.onMouseEvent, s);
        });
        s.addEventListener(MouseEvent.MOUSE_DOWN, s.onMouseEvent, s, false);
        // s.addEventListener(MouseEvent.MOUSE_MOVE, s.onMouseEvent, s);
        // s.addEventListener(MouseEvent.MOUSE_UP, s.onMouseEvent, s);
        // s.addEventListener(MouseEvent.MOUSE_OUT, s.onMouseEvent, s);
        s.addEventListener(Event.ENTER_FRAME, s.onEnterFrame, s);
        return _this;
    }
    Object.defineProperty(ScrollView.prototype, "scrollWidth", {
        /**
         * 滚动宽度
         * 设置0表示不让滚动
         */
        get: function () {
            return this._scrollWidth;
        },
        set: function (v) {
            if (this._scrollWidth == v)
                return;
            this._scrollWidth = v;
            //改变
            this.checkPosition(this.bounceTime);
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(ScrollView.prototype, "scrollHeight", {
        /**
         * 滚动高度
         * 设置0表示不让滚动
         */
        get: function () {
            return this._scrollHeight;
        },
        set: function (v) {
            if (this._scrollHeight == v)
                return;
            this._scrollHeight = v;
            //改变
            this.checkPosition(this.bounceTime);
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(ScrollView.prototype, "maxScrollX", {
        /**
         * 最大滚动坐标x，为负
         */
        get: function () {
            //不能滚动，就是0
            if (!this.scrollWidth)
                return 0;
            //
            return Math.min(this.viewWidth - this.scrollWidth, 0);
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(ScrollView.prototype, "maxScrollY", {
        /**
         * 最大滚动坐标y，为负
         */
        get: function () {
            //不能滚动，就是0
            if (!this.scrollHeight)
                return 0;
            return Math.min(this.viewHeight - this.scrollHeight, 0);
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(ScrollView.prototype, "view", {
        /**
         * 滚动内容的节点容器
         * 注意滚动内容都往这上面加
         */
        get: function () {
            return this._content;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 设置可见区域，可见区域的坐标始终在本地坐标中0,0点位置
     * @method setViewRect
     * @param {number}w 设置可见区域的宽
     * @param {number}h 设置可见区域的高
     * @param {boolean} isVertical 方向
     * @public
     * @since 1.1.1
     */
    ScrollView.prototype.setViewRect = function (w, h, isFull) {
        var s = this;
        //不全屏才设置mask
        if (!isFull) {
            //加遮罩
            s._content.mask = s.maskObj;
            //为了能接收鼠标事件设置_isUsedToMask
            s.maskObj._isUsedToMask = false;
            //绘制
            s.maskObj.clear()
                .beginFill(0)
                .drawRect(0, 0, w, h)
                .endFill();
        }
        //移除遮罩
        else {
            s._content.mask = null;
        }
        //视窗尺寸
        s.viewWidth = w;
        s.viewHeight = h;
        //改变
        this.checkPosition(s.bounceTime);
    };
    ScrollView.prototype.onMouseEvent = function (e) {
        var s = this;
        //点的时候
        if (e.type == MouseEvent.MOUSE_DOWN) {
            s.isRunning = false;
            //阻止冒泡
            e.stopPropagation();
            //标记一下状态
            s.mouseStatus = 1;
            s.lastTouchTime = Date.now();
            //记录点击的位置
            s.downX = e.stageX;
            s.downY = e.stageY;
            s.distX = 0;
            s.distY = 0;
        }
        else if (e.type == MouseEvent.MOUSE_MOVE) {
            //不是down过来的
            if (s.mouseStatus < 1)
                return;
            //计算间隔
            var deltaX = e.stageX - s.downX, deltaY = e.stageY - s.downY, timestamp = Date.now();
            s.downX = e.stageX;
            s.downY = e.stageY;
            s.distX += deltaX;
            s.distY += deltaY;
            var absDistX = Math.abs(s.distX);
            var absDistY = Math.abs(s.distY);
            //上一步是开始的，超出10才滑动
            if (s.mouseStatus == 1 &&
                absDistX < 10 &&
                absDistY < 10) {
                s.lastTouchTime = timestamp;
                return;
            }
            //这个先不加
            // if (s.isLocked) {
            //     if (absDistX > absDistY + s.lockDis) {
            //         deltaY = 0;
            //     } else if (absDistY >= absDistX + s.lockDis) {
            //         deltaX = 0;
            //     }
            // }
            var oriX = s._content.x, oriY = s._content.y;
            deltaX = s.scrollWidth ? deltaX : 0;
            deltaY = s.scrollHeight ? deltaY : 0;
            //计算速度
            var deltaT = timestamp - s.lastTouchTime, sx = 0, sy = 0;
            var newX = oriX + deltaX;
            var newY = oriY + deltaY;
            if (newX > 0 || newX < s.maxScrollX) {
                newX = s.isBounce ? oriX + deltaX / 3 : newX > 0 ? 0 : s.maxScrollX;
            }
            else {
                sx = deltaX / deltaT;
            }
            if (newY > 0 || newY < s.maxScrollY) {
                newY = s.isBounce ? oriY + deltaY / 3 : newY > 0 ? 0 : s.maxScrollY;
            }
            else {
                sy = deltaY / deltaT;
            }
            //记录速度
            s.pushVelocitys(sx, sy);
            s.lastTouchTime = timestamp;
            s._translate(newX, newY);
            //事件处理
            if (s.mouseStatus == 1) {
                s.dispatchEvent(Event.SCROLL_START, {
                    x: -newX,
                    y: -newY,
                    deltaX: oriX - newX,
                    deltaY: oriY - newY
                });
            }
            s.mouseStatus = 2;
        }
        else {
            //超出边界了
            if (s.checkPosition(s.bounceTime)) {
                s.mouseStatus = 0;
                return;
            }
            //状态不是move过来的，重置状态后return
            if (s.mouseStatus != 2) {
                s.mouseStatus = 0;
                return;
            }
            s.mouseStatus = 0;
            var newX = s._content.x, newY = s._content.y, time = 0;
            //有缓冲
            if (s.hasMomentum && s.velocitys.length) {
                //计算速度
                var sum = { x: 0, y: 0 }, totalW = 0;
                for (var i = 0; i < s.velocitys.length; i++) {
                    var v = s.velocitys[i];
                    var w = ScrollView.weight[i];
                    sum.x += v[0] * w;
                    sum.y += v[1] * w;
                    totalW += w;
                }
                s.velocitys.length = 0;
                var sx = sum.x / totalW, sy = sum.y / totalW;
                var momentumX = (s.scrollWidth && Math.abs(sx) > 0.02) ? toMomentum(newX, sx, s.maxScrollX, s.damping) : {
                    destination: newX,
                    duration: 0
                };
                var momentumY = (s.scrollHeight && Math.abs(sy) > 0.02) ? toMomentum(newY, sy, s.maxScrollY, s.damping) : {
                    destination: newY,
                    duration: 0
                };
                newX = momentumX.destination;
                newY = momentumY.destination;
                time = Math.max(momentumX.duration, momentumY.duration);
            }
            if (newX != s._content.x || newY != s._content.y) {
                s._scrollTo(newX, newY, time);
                return;
            }
            s.dispatchEvent(Event.SCROLL_STOP, {
                x: -s._content.x,
                y: -s._content.y,
                deltaX: 0,
                deltaY: 0
            });
        }
    };
    ScrollView.prototype.onEnterFrame = function (e) {
        var s = this;
        var now = Date.now();
        //用户点击交互时需要加
        if (s.mouseStatus && s.lastTouchTime && now - s.lastTouchTime > 100 && now - s.lastTouchTime < 300) {
            s.pushVelocitys(0, 0);
        }
        if (!s.isRunning)
            return;
        //时间到了
        if (now >= s.destTime) {
            s.isRunning = false;
            var _a = s._content, x = _a.x, y = _a.y;
            //移动到最终位置
            s._translate(s.destX, s.destY);
            //检查是否合法，
            if (!s.checkPosition(s.bounceTime)) {
                var data = {
                    x: -s.destX,
                    y: -s.destY,
                    deltaX: x - s.destX,
                    deltaY: y - s.destX,
                };
                s.dispatchEvent(Event.SCROLL_STOP, data);
                if (s.destX == 0 && s.destY == 0) {
                    s.dispatchEvent(Event.SCROLL_TO_HEAD, data);
                }
                if (s.destX == s.maxScrollX && s.destY == s.maxScrollY) {
                    s.dispatchEvent(Event.SCROLL_TO_END, data);
                }
            }
        }
        else {
            now = (now - s.startTime) / s.duration;
            var easing = s.easeFn(now);
            s._translate((s.destX - s.startX) * easing + s.startX, (s.destY - s.startY) * easing + s.startY);
        }
    };
    ScrollView.prototype.pushVelocitys = function (vx, vy) {
        this.velocitys.push([vx, vy]);
        if (this.velocitys.length > ScrollView.weight.length)
            this.velocitys.shift();
    };
    /**
     * 滚到指定的坐标位置
     * @param {number} x 往左横向滚动距离，0到最大横向滚动距离
     * @param {number} y 往上纵向滚动距离，0到最大纵向滚动距离
     * @param {number} time 滚动需要的时间 默认为0 即没有缓动直接到达指定位置，毫秒计
     * @param {Function} easeFn 缓动函数，不传默认用Ease.circOut，从快到慢
     * @public
     */
    ScrollView.prototype.scrollTo = function (x, y, time, easeFn) {
        if (time === void 0) { time = 0; }
        //xy都是相对左上角正向的，所以真正_content的坐标应该取负
        //判断范围
        var _a = this._modifyXY(-x, -y), nx = _a[0], ny = _a[1];
        //真实滚动
        this._scrollTo(nx, ny, time, easeFn);
    };
    /**
     * 从当前位置继续滚动
     * @param {number} x 往左滚动距离
     * @param {number} y 往上滚动距离
     * @param {number} time 滚动需要的时间 默认为0 即没有缓动直接到达指定位置，毫秒计
     * @param {Function} easeFn 缓动函数，不传默认用Ease.circOut，从快到慢
     * @public
     */
    ScrollView.prototype.scrollBy = function (x, y, time, easeFn) {
        if (time === void 0) { time = 0; }
        var s = this;
        //最终的位置
        x = s._content.x - x;
        y = s._content.y - y;
        //判断范围
        var _a = this._modifyXY(x, y), nx = _a[0], ny = _a[1];
        s._scrollTo(nx, ny, time, easeFn);
    };
    /**
     * 真实的滚动，xy一般都是负数
     * @param x
     * @param y
     * @param time
     * @param easeFn 缓动函数，不传默认用Ease.circOut
     * @returns
     */
    ScrollView.prototype._scrollTo = function (x, y, time, easeFn) {
        if (time === void 0) { time = 0; }
        var s = this;
        //判断下
        if (isNaN(x) || isNaN(y))
            return;
        if (!time) {
            s.isRunning = false;
            s._translate(x, y);
        }
        else {
            s.startX = s._content.x;
            s.startY = s._content.y;
            s.startTime = Date.now();
            s.destTime = s.startTime + time;
            s.destX = x;
            s.destY = y;
            s.duration = time;
            s.easeFn = easeFn || Ease.quadOut;
            s.isRunning = true;
        }
    };
    /**
     * _content位置的改变都用这个方法
     * @param x
     * @param y
     */
    ScrollView.prototype._translate = function (x, y) {
        var s = this;
        var _a = s._content, oriX = _a.x, oriY = _a.y;
        s._content.x = x;
        s._content.y = y;
        //事件，位置变了
        if (oriX != x || oriY != y) {
            s.dispatchEvent(Event.SCROLLING, {
                x: -x,
                y: -y,
                deltaX: oriX - x,
                deltaY: oriY - y
            });
        }
    };
    /**
     * 检查当前的位置是否合理，不合理会返回true，且滚动到对应位置
     * @param time
     * @returns
     */
    ScrollView.prototype.checkPosition = function (time) {
        if (time === void 0) { time = 0; }
        //原先坐标
        var _a = this._content, x = _a.x, y = _a.y;
        //矫正坐标
        var _b = this._modifyXY(x, y), nx = _b[0], ny = _b[1];
        // 完全一致，就不处理
        if (x == nx && y == ny)
            return false;
        //滚动
        this._scrollTo(nx, ny, time);
        return true;
    };
    /**
     * 矫正坐标
     * @param x
     * @param y
     * @returns
     */
    ScrollView.prototype._modifyXY = function (x, y) {
        var _a = this, scrollWidth = _a.scrollWidth, maxScrollX = _a.maxScrollX, scrollHeight = _a.scrollHeight, maxScrollY = _a.maxScrollY;
        if (!scrollWidth || x > 0) {
            x = 0;
        }
        else if (x < maxScrollX) {
            x = maxScrollX;
        }
        if (!scrollHeight || y > 0) {
            y = 0;
        }
        else if (y < maxScrollY) {
            y = maxScrollY;
        }
        return [x, y];
    };
    ScrollView.prototype.destroy = function () {
        var s = this;
        //由于操作子级方法被重写了，销毁时移除不了，所以手动操作，用removeChildAt，其他都被重写了
        _super.prototype.removeChildAt.call(this, 0)
            .destroy();
        _super.prototype.removeChildAt.call(this, 0)
            .destroy();
        s.maskObj = null;
        s._content = null;
        s.easeFn = null;
        _super.prototype.destroy.call(this);
    };
    ScrollView.weight = [1, 1.33, 1.66, 2, 2.33];
    return ScrollView;
}(Container));
//将添加与移除的操作统统重写到_content中，待测试，需要维护,TODO。对于list直接不允许使用下面这些方法
Container._childrenOperationMethods.forEach(function (v) {
    Object.defineProperty(ScrollView.prototype, v, {
        value: function () {
            var _a;
            var arg = [];
            for (var _i = 0; _i < arguments.length; _i++) {
                arg[_i] = arguments[_i];
            }
            console.warn("Maybe you want to operate children in its view rather then in it when it is a ScrollView!");
            return (_a = Container.prototype[v]).call.apply(_a, __spreadArrays([this], arg));
            //先不重写了，不方便扩展，还容易出问题，只加提示吧
            // return this._content[v](...arg);
        },
        writable: true,
        enumerable: true,
    });
});
/**
 *
 * @param current 当前位置
 * @param speed 速度。move最后位置到松开的位置/滑动到松开的时间
 * @param lowerMargin
 * @param deceleration
 * @returns
 */
function toMomentum(current, speed, lowerMargin, deceleration) {
    if (deceleration === void 0) { deceleration = 0.0006; }
    //衰减到0的时间
    var duration = Math.abs(speed) / deceleration;
    var destination = current + duration * (speed / 2);
    // console.log(current, speed)
    if (destination < lowerMargin) {
        destination = lowerMargin;
        duration = Math.abs((destination - current) / (speed / 2));
    }
    else if (destination > 0) {
        destination = 0;
        duration = Math.abs(current / (speed / 2));
    }
    return {
        destination: destination,
        duration: duration
    };
}

/**
 * 滚动类的Item基类
 * @class IScrollListItem
 * @public
 * @extends Container
 * @since 2.0.0
 */
var ScrollListItem = /** @class */ (function (_super) {
    __extends(ScrollListItem, _super);
    function ScrollListItem() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    /**
     * 列表滚动时各项item有数据变更时会触发
     * @param data 参数会传入data，也可直接使用this.data
     * @param index data所在数组的索引
     * @protected
     */
    ScrollListItem.prototype.onDataChanged = function (data, index) {
    };
    return ScrollListItem;
}(Container));
/**
 * 滚动列表
 * @class ScrollList
 * @public
 * @extends ScrollView
 * @since 1.0.9
 */
var ScrollList = /** @class */ (function (_super) {
    __extends(ScrollList, _super);
    /**
     * 构造函数
     * @method ScrollList
     * @param {Class} itemClass 可以做为Item的类，比如ScrollListItem，必须具备onDataChanged方法
     * @param {number} itemWidth item宽
     * @param {number} itemHeight item高
     * @param {number} vW 列表的宽
     * @param {number} vH 列表的高
     * @param {boolean} isVertical 是横向滚动还是纵向滚动 默认是纵向
     * @param {number} cols 分几列，默认是1列
     * @since 2.0.0
     */
    function ScrollList(itemClass, itemWidth, itemHeight, vW, vH, isVertical, cols) {
        if (isVertical === void 0) { isVertical = true; }
        if (cols === void 0) { cols = 1; }
        var _this = _super.call(this, vW, vH, 0, 0) || this;
        _this._items = null;
        _this._isInit = 0;
        _this._lastFirstId = -1;
        var s = _this;
        s._instanceType = "ScrollList";
        s._itemW = itemWidth;
        s._itemH = itemHeight;
        s._items = [];
        s._itemClass = itemClass;
        s._itemCount = 0;
        s._cols = cols;
        s._isVertical = isVertical;
        s._updateRowCol();
        //滚动时需要刷新数据
        s.addEventListener(Event.SCROLLING, s.flushData, s);
        return _this;
    }
    Object.defineProperty(ScrollList.prototype, "data", {
        /**
         * 数据列表，
         */
        get: function () {
            return this._data;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(ScrollList.prototype, "scrollWidth", {
        /**
         * list里不允许改变滚动尺寸范围，只能通过数据改变
         */
        get: function () {
            return this._scrollWidth;
        },
        set: function (v) {
            console.warn("ScrollWidth can not be set manually in ScrollLists!");
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(ScrollList.prototype, "scrollHeight", {
        /**
         * list里不允许改变滚动尺寸范围，只能通过数据改变
         */
        get: function () {
            return this._scrollHeight;
        },
        set: function (v) {
            console.warn("ScrollHeight can not set manually in ScrollLists!");
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 设置列表数据
     * @method setData
     * @param {Array} data
     * @param {boolean} isReset 是否重置数据列表。默认为true
     * @since 2.0.0
     */
    ScrollList.prototype.setData = function (data, isReset) {
        if (isReset === void 0) { isReset = true; }
        var s = this;
        data = data || [];
        if (!s._isInit || isReset) {
            s._data = data;
        }
        else {
            s._data = s._data.concat(data);
        }
        s._isInit = 1;
        s._lastFirstId = -1;
        var maxDistance = Math.ceil(s.data.length / s._cols) * s._itemRow;
        s[s._isVertical ? "_scrollHeight" : "_scrollWidth"] = maxDistance;
        //检查一下位置
        if (!s.checkPosition(s.bounceTime)) {
            //没滚动需要刷新数据
            s.flushData();
        }
    };
    ScrollList.prototype.updateData = function (data, isReset) {
        if (isReset === void 0) { isReset = true; }
        console.warn("Method updateData will be abandoned soon,use method setData instead!");
        this.setData(data, isReset);
    };
    ScrollList.prototype.flushData = function (e) {
        var s = this;
        if (!s._isInit)
            return;
        var dimension, antDimension, speed;
        if (s._isVertical) {
            dimension = "y";
            antDimension = "x";
            if (e && e.data)
                speed = e.data.deltaY;
        }
        else {
            dimension = "x";
            antDimension = "y";
            if (e && e.data)
                speed = e.data.deltaX;
        }
        var dis = s._content[dimension];
        var id = dis > 0 ? 0 : (Math.abs(Math.floor(dis / s._itemRow)) - 1) * s._cols;
        //如果dis是0的时候会是-1
        id = Math.max(0, id);
        // console.log(id)
        //确定下和之前记录第一项id是否一致，一致就没必要改了
        if (id == s._lastFirstId)
            return;
        s._lastFirstId = id;
        //重新排数组，尽量最少的数据刷新
        if (speed) {
            for (var r = 0; r < s._cols; r++) {
                //向下滚动时
                if (speed < 0) {
                    s._items.unshift(s._items.pop());
                }
                //向上滚动时
                else {
                    s._items.push(s._items.shift());
                }
            }
        }
        for (var i = 0; i < s._itemCount; i++) {
            var item = s._items[i];
            if (s._isInit == 1) {
                item.index = -1;
            }
            if (item.index !== id) {
                //id在data数组列表内就执行
                if (id < s.data.length) {
                    item.index = id;
                    item.onDataChanged(item.data = s.data[id], id);
                    item.visible = true;
                    //位置
                    item[dimension] = Math.floor(id / s._cols) * s._itemRow;
                    item[antDimension] = (id % s._cols) * s._itemCol;
                }
                else {
                    item.data = null;
                    item.index = -1;
                    item.visible = false;
                    //位置需要刷新吗？
                }
            }
            id++;
        }
        s._isInit = 2;
    };
    /**
     * 设置可见区域，可见区域的坐标始终在本地坐标中0,0点位置
     * @method setViewRect
     * @param {number}w 设置可见区域的宽
     * @param {number}h 设置可见区域的高
     * @param {boolean} isVertical 方向
     * @public
     * @since 2.0.0
     */
    ScrollList.prototype.setViewRect = function (w, h, isVertical) {
        if (isVertical === void 0) { isVertical = true; }
        _super.prototype.setViewRect.call(this, w, h, false);
        var s = this;
        var same = s._isVertical === isVertical;
        s._isVertical = isVertical;
        //有行列时才需要更新
        if (s._itemRow && s._itemCol) {
            s._updateRowCol();
            //先这样偷懒处理
            if (!same) {
                var oriTime = s.bounceTime;
                s.bounceTime = 0;
                s.setData(s._data, true);
                s.bounceTime = oriTime;
            }
            else {
                s.flushData();
            }
        }
    };
    ScrollList.prototype._updateRowCol = function () {
        var s = this, distance;
        if (s._isVertical) {
            s._itemRow = s._itemH;
            s._itemCol = s._itemW;
            distance = s.viewHeight;
            s._scrollWidth = 0;
        }
        else {
            s._itemRow = s._itemW;
            s._itemCol = s._itemH;
            distance = s.viewWidth;
            s._scrollHeight = 0;
        }
        var newCount = (Math.ceil(distance / s._itemRow) + 1) * s._cols;
        if (newCount != s._itemCount) {
            if (newCount > s._itemCount) {
                for (var i = s._itemCount; i < newCount; i++) {
                    var item = new s._itemClass();
                    item.visible = false;
                    item.data = null;
                    s._items.push(item);
                    s._content.addChild(item);
                }
            }
            else {
                for (var i = 0; i < s._itemCount - newCount; i++) {
                    s._content.removeChild(s._items.pop());
                }
            }
            s._itemCount = newCount;
            s._lastFirstId = -1;
        }
    };
    /**
     * 滚动到指定位置
     * @param distance 滚动距离，一般为正
     * @param time 滚动时间，默认0
     */
    ScrollList.prototype.scrollTo = function (distance, time) {
        if (time === void 0) { time = 0; }
        var x = 0, y = 0;
        if (this._isVertical) {
            y = distance;
        }
        else {
            x = distance;
        }
        _super.prototype.scrollTo.call(this, x, y, time);
    };
    /**
     * 从当前位置开始滚动
     * @param distance 滚动距离，一般为正
     * @param time 滚动时间，默认0
     */
    ScrollList.prototype.scrollBy = function (distance, time) {
        if (time === void 0) { time = 0; }
        var x = 0, y = 0;
        if (this._isVertical) {
            y = distance;
        }
        else {
            x = distance;
        }
        _super.prototype.scrollBy.call(this, x, y, time);
    };
    ScrollList.prototype.destroy = function () {
        var s = this;
        s._items = null;
        s._itemClass = null;
        s._data = null;
        _super.prototype.destroy.call(this);
    };
    return ScrollList;
}(ScrollView));
//list不允许操作任何子级
Container._childrenOperationMethods.forEach(function (v) {
    Object.defineProperty(ScrollList.prototype, v, {
        value: function () {
            var _a;
            var arg = [];
            for (var _i = 0; _i < arguments.length; _i++) {
                arg[_i] = arguments[_i];
            }
            console.warn("You'd better do not operate children in a ScrollList or its view!");
            return (_a = Container.prototype[v]).call.apply(_a, __spreadArrays([this], arg));
            //先不重写了
            // console.warn("ScrollLists can not operate children any more!")
        },
        writable: true,
        enumerable: true,
    });
});

/**
 * 帧数从1开始
 * 用于播放动画
 * 帧数监听，已ued给的文件为主，不做补间增加帧数，
 * 暂无setText再加
 * 暂时无矢量图
 * 暂不支持加快播放，锁步时偷偷改timeInterval，默认1000 / FPS
 * s.addEventListener(Event.ENTER_FRAME, func = (e) => {
 *      //这个判断如果只希望执行一次得多加一个条件isInTimeFrame为true，或者及时移除
 *      if (e.target.currentFrame == 66&&e.target.isInTimeFrame) {
 *         e.target.removeEventListener(Event.ENTER_FRAME, func);
 *    }
 * });
 * 锁步时的每帧监听，用>或<判断，及时移除
 * @class MovieClip
 * @since 1.0.0
 * @public
 * @extends Container
 */
var MovieClip = /** @class */ (function (_super) {
    __extends(MovieClip, _super);
    /**
     * 构造函数
     * @method MovieClip
     * @public
     * @param mv VideoEntity格式，这里不给了
     */
    function MovieClip(mv) {
        var _this = _super.call(this) || this;
        /**
         * 锁步将按时间间隔来执行动画
         */
        _this.lockStep = false;
        /**
         * @property _curFrame
         * @type {number}
         * @private
         * @since 2.0.0
         * @default 1
         */
        _this._curFrame = 1;
        /**
         * @property _isPlaying
         * @type {boolean}
         * @private
         * @since 2.0.0
         * @default true
         */
        _this._isPlaying = true;
        /**
         * @property _isFront
         * @type {boolean}
         * @private
         * @default true
         */
        _this._isFront = true;
        /**
         * 中间帧计时
         */
        _this.frameCount = 0;
        /**
         * @property _lastFrame
         * @type {number}
         * @private
         * @default 0
         */
        _this._lastFrame = 0;
        _this.commonDeltaTime = 1000 / 60;
        var s = _this;
        s._instanceType = "MovieClip";
        //初始化
        if (mv)
            s.init(mv);
        console.warn("class MovieClip will be deleted soon,use class SvgaAni instead");
        return _this;
    }
    Object.defineProperty(MovieClip.prototype, "currentFrame", {
        /**
         * mc的当前帧,从1开始
         * @property currentFrame
         * @public
         * @since 1.0.0
         * @type {number}
         * @default 1
         * @readonly
         */
        get: function () {
            return this._curFrame;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(MovieClip.prototype, "isPlaying", {
        /**
         * 当前动画是否处于播放状态
         * @property isPlaying
         * @readOnly
         * @public
         * @since 1.0.0
         * @type {boolean}
         * @default true
         * @readonly
         */
        get: function () {
            return this._isPlaying;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(MovieClip.prototype, "isFront", {
        /**
         * 动画的播放方向,是顺着播还是在倒着播
         * @property isFront
         * @public
         * @since 1.0.0
         * @type {boolean}
         * @default true
         * @readonly
         */
        get: function () {
            return this._isFront;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(MovieClip.prototype, "totalFrames", {
        /**
         * 当前动画的总帧数
         * @property totalFrames
         * @public
         * @since 1.0.0
         * @type {number}
         * @default 0
         * @readonly
         */
        get: function () {
            return this.rawData && this.rawData.frames || 0;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(MovieClip.prototype, "videoWidth", {
        get: function () {
            return this.rawData && this.rawData.videoSize.width;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(MovieClip.prototype, "videoHeight", {
        get: function () {
            return this.rawData && this.rawData.videoSize.height;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 可以手动用init，
     * @param mv
     */
    MovieClip.prototype.init = function (mv) {
        if (!mv)
            return;
        //移除所有子级
        this.removeAllChildren();
        //移除循环监听事件;
        if (this.startAniRangeFun)
            this.removeEventListener(Event.ENTER_FRAME, this.startAniRangeFun, this);
        //记录源数据
        this.rawData = mv;
        //记录基本信息，fps，每秒输出帧数，frames，总帧数，videoSize暂时不管
        //如果fps小于60怎么处理。update时怎么处理
        this.timeInterval = 1000 / mv.FPS;
        this.startTime = Date.now();
        this.startFrame = 1;
        //间隔帧数，
        this.deltaFrame = 60 / mv.FPS;
        this.frameCount = this.deltaFrame;
        this._curFrame = 1;
        //考虑是否要加遮罩，用videoSize，暂时不用，为了性能
        // var mask = new Graphics();
        // mask.beginFill(0xffffff, 1);
        // mask.drawRect(0, 0, mv.videoSize.width, mv.videoSize.height);
        // mask.endFill();
        // this.mask = mask;
        //缓存图片
        if (mv.images && !mv.textures) { //带图片数据的待测试
            mv.textures = {};
            for (var key in mv.images) {
                var src = mv.images[key];
                if (src.indexOf("iVBO") === 0 || src.indexOf("/9j/2w") === 0) {
                    src = 'data:image/png;base64,' + src;
                } //图片链接时的宽高适配再说，暂时没有遇到过
                var imgTag = createImage();
                imgTag.src = src;
                mv.textures[key] = new Texture(new BaseTexture(imgTag)); //这种方法不会缓存进全局
            }
        }
        this.initChildren(mv.sprites);
        //缓存所有图片
        // const images = mv.images;
        // if (mv.hasBeenCached) {
        //     //如已被缓存，则直接取了赋值
        //     for (var keyName in images) {
        //         this.textures[keyName] = TextureCache[keyName];
        //     }
        //     this.initChildren(mv.sprites)
        // } else {
        //     //合图有bug，先不合了
        //     // if (GlobalPro.stageRenderType == RENDERER_TYPE.WEBGL) {
        //     //     //缓存成一张canvas，考虑要不要把所有资源搞成图集
        //     //     DrawAllToCanvas(images, (t) => {
        //     //         this.textures = t;
        //     //         this.initChildren(mv.sprites)
        //     //         //缓存
        //     //         for (var key in this.textures) {
        //     //             Texture.addToCache(this.textures[key], key)
        //     //         }
        //     //         mv.hasBeenCached = true;
        //     //     })
        //     // } else {
        //     //canvas直接缓存
        //     for (var key in images) {
        //         var bitmap = images[key];
        //         // let imgTag = document.createElement('img');
        //         let imgTag = getCreateImage()();
        //         let backCanvas;
        //         if (bitmap.indexOf("iVBO") === 0 || bitmap.indexOf("/9j/2w") === 0) {
        //             imgTag.src = 'data:image/png;base64,' + bitmap;
        //         }
        //         else {
        //             imgTag.src = bitmap;
        //             //这里有问题，再说//这里估计是直接用图片链接的，为了适配画在canvas，以后遇到再说
        //             // if (frames[0] && frames[0].layout) {
        //             //     backCanvas = document.createElement('canvas');
        //             //     backCanvas.width = frames[0].layout.width
        //             //     backCanvas.height = frames[0].layout.height
        //             //     imgTag.onload = function () {
        //             //         backCanvas.getContext('2d').drawImage(imgTag, 0, 0, frames[0].layout.width, frames[0].layout.height)
        //             //     }
        //             // }
        //         }
        //         this.textures[key] = Texture.from(backCanvas || imgTag);
        //         // this.textures[key].once("loaded",()=>{
        //         //     是否监听加载完成？
        //         // })
        //         //考虑到key和已有缓存冲突，svga的都单独自己缓存，外部不可用，以后有时间搞
        //         Texture.addToCache(this.textures[key], key)
        //     }
        //     mv.hasBeenCached = true;
        //     this.initChildren(mv.sprites)
        //     // }
        // }
    };
    MovieClip.prototype.initChildren = function (sprites) {
        for (var i = 0, len = sprites.length; i < len; i++) {
            var ele = sprites[i];
            if (ele.imageKey) {
                // var child = new Sprite(this.textures[ele.imageKey]);
                var child = this.addChild(new Sprite(this.rawData.textures ?
                    this.rawData.textures[ele.imageKey] : //自身没存的，取全局的，有图片单独处理出去
                    TextureCache[ele.imageKey] ||
                        TextureCache[ele.imageKey + ".png"] || null));
                //直接赋值矩阵
                child["frames"] = ele.frames;
                //透明度处理
                if (ele.frames[0].alpha < 0.05) {
                    // child.visible = false;
                    child.alpha = 0;
                }
                else {
                    child.alpha = ele.frames[0].alpha;
                    //透明度不为0才赋值吧
                    child.transform.localMatrix.copy(ele.frames[0].transform);
                    child.transform._parentID = -1;
                }
                //记录一个源数据
                child["framesOri"] = ele.frames;
                //记录一个源imageKey
                child["imageKey"] = ele.imageKey;
                //记录一个标识
                // child["matteKey"] = ele.matteKey;
            }
        }
    };
    /**
     *
     * @param imagekey 对应的imagekey
     * @param imageUrl 图片路径，以后考虑支持多种形式
     */
    MovieClip.prototype.setImage = function (imagekey, imageUrl) {
        //先获取原先贴图，为了宽高适配，，这种如何保证base64已经加载完毕，考虑lottie的图片宽高信息存过来？
        var cs = []; //找都找了，就全记录吧
        for (var i = 0; i < this.children.length; i++) {
            if (this.children[i]["imageKey"] == imagekey) {
                cs.push(this.children[i]);
            }
        }
        if (!cs.length)
            return;
        var texture = cs[0].texture;
        var width = texture.width;
        var height = texture.height;
        var image = createImage();
        image.onload = function () {
            var newTexture;
            if (image.width == width && image.height == height) {
                newTexture = Texture.from(image);
            }
            else {
                var canvas = createCanvas(); //document.createElement("canvas");
                canvas.width = width;
                canvas.height = height;
                var ctx = canvas.getContext("2d");
                //适配绘制,为了全部显示在canvas中
                var scaleCan = width / height;
                var scale = image.width / image.height;
                if (scaleCan > scale) {
                    //定高
                    ctx.drawImage(image, 0, 0, image.width, image.height, (width - scale * height) / 2, 0, scale * height, height);
                }
                else {
                    //定宽
                    ctx.drawImage(image, 0, 0, image.width, image.height, 0, (height - width / scale) / 2, width, width / scale);
                }
                newTexture = Texture.fromCanvas(canvas);
            }
            //修改相应sprite
            cs.forEach(function (c) { c.texture = newTexture; });
        };
        image.src = imageUrl;
    };
    /**
     * 调用止方法将停止当前帧
     * @method stop
     * @public
     * @since 1.0.0
     */
    MovieClip.prototype.stop = function () {
        var s = this;
        s._isPlaying = false;
    };
    /**
     * 将播放头向后移一帧并停在下一帧,如果本身在最后一帧则不做任何反应
     * @method nextFrame
     * @since 1.0.0
     * @public
     */
    MovieClip.prototype.nextFrame = function () {
        var s = this;
        if (s._curFrame < s.totalFrames) {
            s._curFrame++;
        }
        s._isPlaying = false;
    };
    /**
     * 将播放头向前移一帧并停在下一帧,如果本身在第一帧则不做任何反应
     * @method prevFrame
     * @since 1.0.0
     * @public
     */
    MovieClip.prototype.prevFrame = function () {
        var s = this;
        if (s._curFrame > 1) {
            s._curFrame--;
        }
        s._isPlaying = false;
    };
    /**
     * 将播放头跳转到指定帧并停在那一帧,如果本身在第一帧则不做任何反应
     * @method gotoAndStop
     * @public
     * @since 1.0.0
     * @param {number} frameIndex 批定帧的帧数或指定帧的标签名
     */
    MovieClip.prototype.gotoAndStop = function (frameIndex) {
        var s = this;
        s._isPlaying = false;
        if (frameIndex > s.totalFrames) {
            frameIndex = s.totalFrames;
        }
        if (frameIndex < 1) {
            frameIndex = 1;
        }
        s._curFrame = frameIndex;
    };
    /**
     * 如果当前时间轴停在某一帧,调用此方法将继续播放.
     * @method play
     * @public
     * @since 1.0.0
     */
    MovieClip.prototype.play = function (isFront) {
        if (isFront === void 0) { isFront = true; }
        var s = this;
        s.frameCount = s.deltaFrame;
        s.startTime = Date.now();
        s.startFrame = s._curFrame;
        s._isPlaying = true;
        s._isFront = isFront;
    };
    Object.defineProperty(MovieClip.prototype, "isInTimeFrame", {
        /**
         * 刚执行到的帧数，用于帧监听时判断用，刚好执行到当前帧，而不是之前保留的状态
         * 不是60fps的videoItem的中间有几帧curFrame会不变，判断只执行一次监听时会出错，刚好动画满帧60fps时就无所谓
         */
        get: function () {
            //相等时就是刚开始的curFrame
            return this.frameCount == this.deltaFrame;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 将播放头跳转到指定帧并从那一帧开始继续播放
     * @method gotoAndPlay
     * @public
     * @since 1.0.0
     * @param {number} frameIndex 批定帧的帧数或指定帧的标签名
     * @param {boolean} isFront 跳到指定帧后是向前播放, 还是向后播放.不设置些参数将默认向前播放
     */
    MovieClip.prototype.gotoAndPlay = function (frameIndex, isFront) {
        if (isFront === void 0) { isFront = true; }
        var s = this;
        s._isFront = isFront;
        s._isPlaying = true;
        if (frameIndex > s.totalFrames) {
            frameIndex = s.totalFrames;
        }
        if (frameIndex < 1) {
            frameIndex = 1;
        }
        s.frameCount = s.deltaFrame;
        s.startTime = Date.now();
        s._curFrame = frameIndex;
        s.startFrame = s._curFrame;
    };
    /**
     * 优先级最高，会覆盖
     * @param beginFrame 默认1
     * @param endFrame 默认 this.totalFrames
     * @param loops 默认1 小于等于0为无线循环，
     * @param callback 动画循环次数播放结束时回调，无限循环时不会有回调
     */
    MovieClip.prototype.startAniRange = function (beginFrame, endFrame, loops, callback) {
        var _this = this;
        if (beginFrame === void 0) { beginFrame = 1; }
        if (endFrame === void 0) { endFrame = this.totalFrames; }
        if (loops === void 0) { loops = 1; }
        //兼容下传0或null等等
        beginFrame = beginFrame || 1;
        endFrame = endFrame || this.totalFrames;
        loops = loops || 0;
        loops = Math.max(0, loops); //去掉负数
        if (beginFrame < 1) {
            beginFrame = 1;
        }
        if (beginFrame > this.totalFrames) {
            beginFrame = this.totalFrames;
        }
        if (endFrame < 1) {
            endFrame = 1;
        }
        if (endFrame > this.totalFrames) {
            endFrame = this.totalFrames;
        }
        if (beginFrame === endFrame) {
            this.gotoAndStop(beginFrame);
            //如果相等
            return;
        }
        else if (beginFrame < endFrame) {
            this._isFront = true;
        }
        else {
            this._isFront = false;
            // var temp = beginFrame;//不能颠倒，待测试
            // beginFrame = endFrame;
            // endFrame = temp;
        }
        //移除原先的绑定吧
        if (this.startAniRangeFun)
            this.removeEventListener(Event.ENTER_FRAME, this.startAniRangeFun, this);
        this._curFrame = beginFrame;
        //赋值count最大
        this.frameCount = this.deltaFrame;
        this.startTime = Date.now();
        this.startFrame = this._curFrame;
        this._isPlaying = true;
        var loopCount = loops ? (loops + 0.5 >> 0) : Infinity;
        this.addEventListener(Event.ENTER_FRAME, this.startAniRangeFun = function (e) {
            if (e.target._isFront) {
                //用大于等于可以避免锁步时出现的问题
                if (e.target.currentFrame >= endFrame || e.target._endMark) {
                    loopCount--;
                    if (loopCount <= 0) {
                        e.target.gotoAndStop(endFrame);
                        e.target.removeEventListener(Event.ENTER_FRAME, _this.startAniRangeFun, _this);
                        _this.startAniRangeFun = null;
                        callback && callback();
                    }
                    else {
                        e.target.gotoAndPlay(beginFrame);
                    }
                }
            }
            else {
                if (e.target.currentFrame <= beginFrame || e.target._endMark) {
                    loopCount--;
                    if (loopCount <= 0) {
                        e.target.gotoAndStop(beginFrame);
                        e.target.removeEventListener(Event.ENTER_FRAME, _this.startAniRangeFun, _this);
                        _this.startAniRangeFun = null;
                        callback && callback();
                    }
                    else {
                        e.target.gotoAndPlay(endFrame, false);
                    }
                }
            }
        }, this);
    };
    MovieClip.prototype.updateFrame = function () {
        var s = this;
        //1帧的时候也有相应的frameCount，无用，return
        if (s.totalFrames == 0 || s.totalFrames == 1)
            return;
        var isNeedUpdate = false;
        if (s._lastFrame != s._curFrame) {
            //帧不相等
            isNeedUpdate = true;
            s._lastFrame = s._curFrame;
            //锁步的时候
            s.startTime = Date.now();
            s.startFrame = s._curFrame;
            s._endMark = false;
        }
        else {
            if (s._isPlaying) {
                if (s.lockStep) {
                    isNeedUpdate = s.getCurFrameWhenLockStep();
                }
                else {
                    if (--s.frameCount == 0) {
                        s.frameCount = s.deltaFrame;
                        isNeedUpdate = true;
                        if (s._isFront) {
                            s._curFrame++;
                            if (s._curFrame > s.totalFrames) {
                                s._curFrame = 1;
                            }
                        }
                        else {
                            s._curFrame--;
                            if (s._curFrame < 1) {
                                s._curFrame = s.totalFrames;
                            }
                        }
                        s._lastFrame = s._curFrame;
                    }
                }
            }
        }
        //如果需要更新
        if (isNeedUpdate) {
            //对每个child还原对应的transform，alpha为0的默认visible设为false,避免计算
            for (var i = 0, len = s.children.length; i < len; i++) {
                var child = s.children[i];
                //只修改动画加入的child，不修改手动加入的，,所以想要修改动画中的元素属性，直接去掉frames属性，将不会执行动画
                if (child["frames"] && child["frames"][s._curFrame - 1]) {
                    var frame = child["frames"][s._curFrame - 1];
                    //layout不晓得干嘛用，暂不管
                    if (frame.alpha < 0.05) {
                        // child.visible = false;
                        child.alpha = 0;
                    }
                    else {
                        // child.visible = true;
                        child.alpha = frame.alpha;
                        //先判断transform是否相等
                        if (!Matrix.isEqual(child.transform.localMatrix, frame.transform)) {
                            child.transform.localMatrix.copy(frame.transform);
                            child.transform._parentID = -1;
                        }
                        //遮罩
                        if (frame.maskPath) {
                            if (!child["cusMask"])
                                child["cusMask"] = new Shape();
                            //@ts-ignore ，需要记载child里
                            if (!child.mask)
                                child.mask = child.addChild(child["cusMask"]);
                            var mask = child.mask;
                            MovieClip.drawBezierShape(mask, frame.maskPath);
                        }
                        else if (child.mask) {
                            //@ts-ignore移除
                            child.removeChild(child.mask);
                            child.mask = null;
                        }
                    }
                }
            }
            //事件播放结束监听
            if (!s.lockStep) {
                if (((s._curFrame == 1 && !s._isFront) || (s._curFrame == s.totalFrames && s._isFront)) && s.hasEventListener(Event.END_FRAME)) {
                    s.dispatchEvent(Event.END_FRAME, {
                        frameIndex: s._curFrame,
                        frameName: "endFrame"
                    });
                }
            }
            else {
                //锁步的时候另外判断
                if (s._endMark && s.hasEventListener(Event.END_FRAME)) {
                    s.dispatchEvent(Event.END_FRAME, {
                        frameIndex: s._curFrame,
                        frameName: "endFrame"
                    });
                }
            }
        }
    };
    MovieClip.prototype.getCurFrameWhenLockStep = function () {
        var dateNow = Date.now();
        //相差
        var deltaFrame = ((dateNow - this.startTime) / this.timeInterval) >> 0;
        //间隔帧数与上一帧一致，就不执行
        if (deltaFrame == this.lastDeltaFrame) {
            //设置不等
            this.frameCount = 0;
            return false;
        }
        this._endMark = false;
        //相等，刚好执行切换
        this.frameCount = this.deltaFrame;
        this.lastDeltaFrame = deltaFrame;
        if (this._isFront) {
            //取余数
            this._curFrame = (this.startFrame + deltaFrame) % this.totalFrames;
            if (this._curFrame == 0) {
                this._curFrame = this.totalFrames;
                this._endMark = true;
            }
            //当上一帧大于_curFrame,并且上一帧不是totalFrames时，说明跳过了最后一帧
            else if (this._lastFrame > this._curFrame &&
                this._lastFrame != this.totalFrames) {
                this._endMark = true;
            }
        }
        else {
            this._curFrame = (this.startFrame - deltaFrame) % this.totalFrames;
            if (this._curFrame == 0) {
                this._curFrame = this.totalFrames;
            }
            else if (this._curFrame < 0) {
                this._curFrame += this.totalFrames;
            }
            if (this._curFrame == 1) {
                this._endMark = true;
            }
            //当上一帧小于_curFrame,并且上一帧不是1时，说明跳过了第一帧
            else if (this._lastFrame < this._curFrame &&
                this._lastFrame != 1) {
                this._endMark = true;
            }
        }
        this._lastFrame = this._curFrame;
        return true;
    };
    /**
     * 重写刷新
     * @method update
     * @public
     * @since 1.0.0
     */
    MovieClip.prototype.update = function () {
        //更新帧数据
        this.updateFrame();
        _super.prototype.update.call(this);
    };
    MovieClip.prototype.destroy = function () {
        //todo-清除相应的数据引用
        this.rawData = null;
        _super.prototype.destroy.call(this);
    };
    /**
     * 用源数据拷贝一份，用相应参数
     * @param frames 源数据
     * @param x 偏移x，默认0
     * @param y 偏移y，默认0
     * @param scaleX 相对缩放x，默认1
     * @param scaleY 相对缩放y，默认1
     * @param rotation 相对旋转,角度制，默认0
     * @param anchorX 相对锚点x，默认0
     * @param anchorY 相对锚点y，默认0
     */
    MovieClip.deepCopyFrames = function (frames, x, y, scaleX, scaleY, rotation, anchorX, anchorY) {
        if (x === void 0) { x = 0; }
        if (y === void 0) { y = 0; }
        if (scaleX === void 0) { scaleX = 1; }
        if (scaleY === void 0) { scaleY = 1; }
        if (rotation === void 0) { rotation = 0; }
        if (anchorX === void 0) { anchorX = 0; }
        if (anchorY === void 0) { anchorY = 0; }
        var cf = [];
        rotation *= Math.PI / 180;
        //@ts-ignore
        var lt = {};
        lt.a = Math.cos(rotation) * scaleX;
        lt.b = Math.sin(rotation) * scaleX;
        lt.c = -Math.sin(rotation) * scaleY;
        lt.d = Math.cos(rotation) * scaleY;
        lt.tx = x + anchorX - ((anchorX * lt.a) + (anchorY * lt.c));
        lt.ty = y + anchorY - ((anchorX * lt.b) + (anchorY * lt.d));
        for (var j = 0; j < frames.length; j++) {
            var frame = frames[j];
            var pt = frame.transform;
            var f = { alpha: 0, transform: null };
            //透明度
            f.alpha = frame.alpha;
            f.transform = {
                a: (lt.a * pt.a) + (lt.b * pt.c),
                b: (lt.a * pt.b) + (lt.b * pt.d),
                c: (lt.c * pt.a) + (lt.d * pt.c),
                d: (lt.c * pt.b) + (lt.d * pt.d),
                tx: (lt.tx * pt.a) + (lt.ty * pt.c) + pt.tx,
                ty: (lt.tx * pt.b) + (lt.ty * pt.d) + pt.ty,
            };
            cf.push(f);
        }
        return cf;
    };
    /**
     * 根据数据获取遮罩，或更新遮罩，暂时用于遮罩，以后可能用于矢量图
     * @param mask
     * @param data
     * @param useStyle 是否应用样式，一般用于遮罩时不需要，默认false
     * @returns
     */
    MovieClip.drawBezierShape = function (mask, data, useStyle) {
        if (mask === void 0) { mask = new Shape; }
        if (useStyle === void 0) { useStyle = false; }
        mask.clear();
        var styles = data._styles;
        if (useStyle && styles) { //待测试，两个都有的时候是否能正常绘制，毕竟都执行了beginPath
            if (styles.stroke) {
                mask.beginStroke(rgb2hex$1(styles.stroke), styles.strokeWidth || undefined, styles.lineCap || undefined, styles.lineJoin || undefined, styles.miterLimit || undefined, styles.stroke[3]);
            }
            if (styles.fill) {
                mask.beginFill(rgb2hex$1(styles.fill), styles.fill[3]);
            }
            // if (styles && styles.lineDash) {
            //     ctx.setLineDash(styles.lineDash);
            // }
        }
        else {
            //简单绘制
            mask.beginFill();
        }
        //会用到的，再说TODO
        if (data._transform) {
            //用于修改所有路径的矩阵数据
            mask.transform.localMatrix.copy(data._transform);
            mask.transform._parentID = -1;
        }
        var currentPoint = { x: 0, y: 0, x1: 0, y1: 0, x2: 0, y2: 0 };
        var validMethods = 'MLHVCSQRZmlhvcsqrz';
        var d = data._d.replace(/([a-zA-Z])/g, '|||$1 ').replace(/,/g, ' ');
        d.split('|||').forEach(function (segment) {
            if (segment.length == 0)
                return;
            var firstLetter = segment.substr(0, 1);
            if (validMethods.indexOf(firstLetter) >= 0) {
                var args = segment.substr(1).trim().split(" ");
                switch (firstLetter) {
                    case 'M':
                        currentPoint.x = Number(args[0]);
                        currentPoint.y = Number(args[1]);
                        mask.moveTo(currentPoint.x, currentPoint.y);
                        break;
                    case 'm':
                        currentPoint.x += Number(args[0]);
                        currentPoint.y += Number(args[1]);
                        mask.moveTo(currentPoint.x, currentPoint.y);
                        break;
                    case 'L':
                        currentPoint.x = Number(args[0]);
                        currentPoint.y = Number(args[1]);
                        mask.lineTo(currentPoint.x, currentPoint.y);
                        break;
                    case 'l':
                        currentPoint.x += Number(args[0]);
                        currentPoint.y += Number(args[1]);
                        mask.lineTo(currentPoint.x, currentPoint.y);
                        break;
                    case 'H':
                        currentPoint.x = Number(args[0]);
                        mask.lineTo(currentPoint.x, currentPoint.y);
                        break;
                    case 'h':
                        currentPoint.x += Number(args[0]);
                        mask.lineTo(currentPoint.x, currentPoint.y);
                        break;
                    case 'V':
                        currentPoint.y = Number(args[0]);
                        mask.lineTo(currentPoint.x, currentPoint.y);
                        break;
                    case 'v':
                        currentPoint.y += Number(args[0]);
                        mask.lineTo(currentPoint.x, currentPoint.y);
                        break;
                    case 'C':
                        currentPoint.x1 = Number(args[0]);
                        currentPoint.y1 = Number(args[1]);
                        currentPoint.x2 = Number(args[2]);
                        currentPoint.y2 = Number(args[3]);
                        currentPoint.x = Number(args[4]);
                        currentPoint.y = Number(args[5]);
                        mask.bezierCurveTo(currentPoint.x1, currentPoint.y1, currentPoint.x2, currentPoint.y2, currentPoint.x, currentPoint.y);
                        break;
                    case 'c':
                        currentPoint.x1 = currentPoint.x + Number(args[0]);
                        currentPoint.y1 = currentPoint.y + Number(args[1]);
                        currentPoint.x2 = currentPoint.x + Number(args[2]);
                        currentPoint.y2 = currentPoint.y + Number(args[3]);
                        currentPoint.x += Number(args[4]);
                        currentPoint.y += Number(args[5]);
                        mask.bezierCurveTo(currentPoint.x1, currentPoint.y1, currentPoint.x2, currentPoint.y2, currentPoint.x, currentPoint.y);
                        break;
                    case 'S':
                        if (currentPoint.x1 && currentPoint.y1 && currentPoint.x2 && currentPoint.y2) {
                            currentPoint.x1 = currentPoint.x - currentPoint.x2 + currentPoint.x;
                            currentPoint.y1 = currentPoint.y - currentPoint.y2 + currentPoint.y;
                            currentPoint.x2 = Number(args[0]);
                            currentPoint.y2 = Number(args[1]);
                            currentPoint.x = Number(args[2]);
                            currentPoint.y = Number(args[3]);
                            mask.bezierCurveTo(currentPoint.x1, currentPoint.y1, currentPoint.x2, currentPoint.y2, currentPoint.x, currentPoint.y);
                        }
                        else {
                            currentPoint.x1 = Number(args[0]);
                            currentPoint.y1 = Number(args[1]);
                            currentPoint.x = Number(args[2]);
                            currentPoint.y = Number(args[3]);
                            mask.quadraticCurveTo(currentPoint.x1, currentPoint.y1, currentPoint.x, currentPoint.y);
                        }
                        break;
                    case 's':
                        if (currentPoint.x1 && currentPoint.y1 && currentPoint.x2 && currentPoint.y2) {
                            currentPoint.x1 = currentPoint.x - currentPoint.x2 + currentPoint.x;
                            currentPoint.y1 = currentPoint.y - currentPoint.y2 + currentPoint.y;
                            currentPoint.x2 = currentPoint.x + Number(args[0]);
                            currentPoint.y2 = currentPoint.y + Number(args[1]);
                            currentPoint.x += Number(args[2]);
                            currentPoint.y += Number(args[3]);
                            mask.bezierCurveTo(currentPoint.x1, currentPoint.y1, currentPoint.x2, currentPoint.y2, currentPoint.x, currentPoint.y);
                        }
                        else {
                            currentPoint.x1 = currentPoint.x + Number(args[0]);
                            currentPoint.y1 = currentPoint.y + Number(args[1]);
                            currentPoint.x += Number(args[2]);
                            currentPoint.y += Number(args[3]);
                            mask.quadraticCurveTo(currentPoint.x1, currentPoint.y1, currentPoint.x, currentPoint.y);
                        }
                        break;
                    case 'Q':
                        currentPoint.x1 = Number(args[0]);
                        currentPoint.y1 = Number(args[1]);
                        currentPoint.x = Number(args[2]);
                        currentPoint.y = Number(args[3]);
                        mask.quadraticCurveTo(currentPoint.x1, currentPoint.y1, currentPoint.x, currentPoint.y);
                        break;
                    case 'q':
                        currentPoint.x1 = currentPoint.x + Number(args[0]);
                        currentPoint.y1 = currentPoint.y + Number(args[1]);
                        currentPoint.x += Number(args[2]);
                        currentPoint.y += Number(args[3]);
                        mask.quadraticCurveTo(currentPoint.x1, currentPoint.y1, currentPoint.x, currentPoint.y);
                        break;
                    case 'A':
                        break;
                    case 'a':
                        break;
                    case 'Z':
                    case 'z':
                        mask.closePath();
                        break;
                }
            }
        });
        if (useStyle && styles) { //待测试，两者是否都能执行
            if (styles.fill)
                mask.endFill();
            if (styles.stroke)
                mask.endStroke();
        }
        else {
            //简单，直接绘制
            mask.endFill();
        }
        //返回
        return mask;
    };
    return MovieClip;
}(Container));

/**
 * svga动画的承载显示类
 */
var SvgaAni = /** @class */ (function (_super) {
    __extends(SvgaAni, _super);
    // /**
    //  * 用于控制动画，这里面的按帧数计，animationClip.totalTime是总帧数，因为文件标记的是帧，而不是时间
    //  */
    // animationClip: AnimationClip;
    function SvgaAni(data) {
        var _this = _super.call(this, data) || this;
        _this._instanceType = "SvgaAni";
        return _this;
    }
    Object.defineProperty(SvgaAni.prototype, "totalTime", {
        /**
         * 总时间，秒计
         */
        get: function () {
            return this.rawData && this.rawData.frames * (1 / this.fps) || 0;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(SvgaAni.prototype, "totalFrames", {
        /**
         * 总帧数
         */
        get: function () {
            return this.rawData && this.rawData.frames || 0;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(SvgaAni.prototype, "videoWidth", {
        /**
         * 动画显示宽度
         */
        get: function () {
            return this.rawData && this.rawData.videoSize.width || null;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(SvgaAni.prototype, "videoHeight", {
        /**
         * 动画显示高度
         */
        get: function () {
            return this.rawData && this.rawData.videoSize.height || null;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(SvgaAni.prototype, "fps", {
        /**
         * 每秒刷新帧数，没设置过直接用数据里的
         */
        get: function () {
            //没设置过就用数据里的
            return this._fps || this.rawData && this.rawData.FPS || null;
        },
        set: function (v) {
            this._fps = v;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 初始化方法
     * @param data
     * @returns
     */
    SvgaAni.prototype.init = function (data) {
        var _this = this;
        if (!data || data == this.rawData)
            return;
        //记录原数据
        this.rawData = data;
        //移除所有子级，后续考虑销毁
        this.removeAllChildren();
        //缓存图片
        if (data.images && !data.textures) { //带图片数据的待测试
            data.textures = {};
            for (var key in data.images) {
                var src = data.images[key];
                if (src.indexOf("iVBO") === 0 || src.indexOf("/9j/2w") === 0) {
                    src = 'data:image/png;base64,' + src;
                } //图片链接时的宽高适配再说，暂时没有遇到过
                var imgTag = createImage();
                imgTag.src = src;
                data.textures[key] = new Texture(new BaseTexture(imgTag)); //这种方法不会缓存进全局
            }
        }
        var tracks = [];
        //处理子级
        data.sprites.forEach(function (ele) {
            if (!ele.imageKey)
                return;
            var sprite = _this.addChild(new Sprite(_this.rawData.textures ?
                _this.rawData.textures[ele.imageKey] : //自身没存的，取全局的，有图片单独处理出去
                TextureCache[ele.imageKey] ||
                    TextureCache[ele.imageKey + ".png"] || null));
            //记录一下用到的图片标识，否则将找不到该显示对象;
            sprite["imageKey"] = ele.imageKey;
            tracks.push(new SvgaTrack(sprite, ele.frames));
        });
        //初始值设置下
        tracks.forEach(function (t) { t.resetValue(); });
        //合成所有时间轴，总时间按总帧数传，其实可能应该用this.totalFrames-1的，无所谓了，只是最后一帧停留了一帧
        if (!this.animationClip) {
            this.animationClip = new AnimationClip(tracks, this.totalFrames);
        }
        else {
            this.animationClip.init(tracks, this.totalFrames);
        }
        //数据更新
        this._onRawDataUpdate();
    };
    /**
     * 添加一个动画部件，主要用于换装添加部件
     * @param imageKey 用于查找图层对应动画的key值，只找首个用key的图层，所以建议视觉保证使用唯一
     * @param child 需要设置动画的显示对象
     * @param index 需要显示的层级
     * @param x 调整位置x
     * @param y 调整位置y
     * @param scaleX
     * @param scaleY
     * @param rotation
     * @param anchorX
     * @param anchorY
     * @returns 返回添加的部件
     */
    SvgaAni.prototype.addAniPart = function (imageKey, child, index, x, y, scaleX, scaleY, rotation, anchorX, anchorY) {
        if (!child || !imageKey || !this.rawData || !this.animationClip)
            return;
        var oriFrames, sprites = this.rawData.sprites;
        for (var i = 0; i < sprites.length; i++) {
            if (sprites[i].imageKey == imageKey) {
                oriFrames = sprites[i].frames;
                break;
            }
        }
        if (!oriFrames) {
            console.warn("no matched data for " + imageKey);
            return;
        }
        var frames = SvgaAni.deepCopyFrames(oriFrames, x, y, scaleX, scaleY, rotation, anchorX, anchorY);
        //总帧数肯定一样的，直接往tracks里push吧
        this.animationClip["tracks"].push(new SvgaTrack(this.addChildAt(child, index), frames));
        //返回添加的部分
        return child;
    };
    /**
     * 移动部件
     * @param child
     * @returns
     */
    SvgaAni.prototype.removeAniPart = function (child) {
        //先从父级移除
        this.removeChild(child);
        //再从tracks移除，为了不想加polyfill，不用find或findIndex
        var tracks = this.animationClip["tracks"];
        //找出track；
        for (var i = 0; i < tracks.length; i++) {
            if (tracks[i]["obj"] == child) {
                tracks.splice(i, 1);
                break;
            }
        }
        return child;
    };
    /**
     * 给图层修改图片，一般用于出奖动效的奖品图片的替换，尺寸不一致时会做居中适配
     * @param imagekey 会查找所有用了imagekey的图层
     * @param imageUrl 图片路径
     */
    SvgaAni.prototype.setImage = function (imagekey, imageUrl) {
        //先获取原先贴图，为了宽高适配，，这种如何保证base64已经加载完毕，考虑lottie的图片宽高信息存过来？
        var cs = this.getSpritesByImageKey(imagekey);
        if (!cs.length)
            return;
        var texture = cs[0].texture;
        var width = texture.width;
        var height = texture.height;
        var image = createImage();
        image.onload = function () {
            var newTexture;
            if (image.width == width && image.height == height) {
                newTexture = Texture.from(image);
            }
            else {
                var canvas = createCanvas(); //document.createElement("canvas");
                canvas.width = width;
                canvas.height = height;
                var ctx = canvas.getContext("2d");
                //适配绘制,为了全部显示在canvas中
                var scaleCan = width / height;
                var scale = image.width / image.height;
                if (scaleCan > scale) {
                    //定高
                    ctx.drawImage(image, 0, 0, image.width, image.height, (width - scale * height) / 2, 0, scale * height, height);
                }
                else {
                    //定宽
                    ctx.drawImage(image, 0, 0, image.width, image.height, 0, (height - width / scale) / 2, width, width / scale);
                }
                newTexture = Texture.fromCanvas(canvas);
            }
            //修改相应sprite
            cs.forEach(function (c) { c.texture = newTexture; });
        };
        image.src = imageUrl;
    };
    /**
     * 给对应图层修改纹理，直接替换，所以建议原纹理和替换纹理尺寸一致
     * @param imagekey 会查找所有用了imagekey的图层
     * @param texture 纹理
     */
    SvgaAni.prototype.setTexture = function (imagekey, texture) {
        var cs = this.getSpritesByImageKey(imagekey);
        cs.forEach(function (c) { c.texture = texture; });
    };
    /**
     * 根据imagekey获取所有用到过的图层
     * @param imagekey
     * @returns
     */
    SvgaAni.prototype.getSpritesByImageKey = function (imagekey) {
        var cs = []; //找都找了，就全记录吧
        for (var i = 0; i < this.children.length; i++) {
            if (this.children[i]["imageKey"] == imagekey) {
                cs.push(this.children[i]);
            }
        }
        return cs;
    };
    /**
     * 用源数据拷贝一份，用相应参数，并未拷贝遮罩或矢量数据
     * @param frames 源数据
     * @param x 偏移x，默认0
     * @param y 偏移y，默认0
     * @param scaleX 相对缩放x，默认1
     * @param scaleY 相对缩放y，默认1
     * @param rotation 相对旋转,角度制，默认0
     * @param anchorX 相对锚点x，默认0
     * @param anchorY 相对锚点y，默认0
     */
    SvgaAni.deepCopyFrames = function (frames, x, y, scaleX, scaleY, rotation, anchorX, anchorY) {
        if (x === void 0) { x = 0; }
        if (y === void 0) { y = 0; }
        if (scaleX === void 0) { scaleX = 1; }
        if (scaleY === void 0) { scaleY = 1; }
        if (rotation === void 0) { rotation = 0; }
        if (anchorX === void 0) { anchorX = 0; }
        if (anchorY === void 0) { anchorY = 0; }
        var cf = [];
        rotation *= Math.PI / 180;
        //@ts-ignore
        var lt = {};
        lt.a = Math.cos(rotation) * scaleX;
        lt.b = Math.sin(rotation) * scaleX;
        lt.c = -Math.sin(rotation) * scaleY;
        lt.d = Math.cos(rotation) * scaleY;
        lt.tx = x + anchorX - ((anchorX * lt.a) + (anchorY * lt.c));
        lt.ty = y + anchorY - ((anchorX * lt.b) + (anchorY * lt.d));
        for (var j = 0; j < frames.length; j++) {
            var frame = frames[j];
            var pt = frame.transform;
            var f = { alpha: 0, transform: null };
            //透明度
            f.alpha = frame.alpha;
            f.transform = {
                a: (lt.a * pt.a) + (lt.b * pt.c),
                b: (lt.a * pt.b) + (lt.b * pt.d),
                c: (lt.c * pt.a) + (lt.d * pt.c),
                d: (lt.c * pt.b) + (lt.d * pt.d),
                tx: (lt.tx * pt.a) + (lt.ty * pt.c) + pt.tx,
                ty: (lt.tx * pt.b) + (lt.ty * pt.d) + pt.ty,
            };
            cf.push(f);
        }
        return cf;
    };
    return SvgaAni;
}(AnimationNode));
var SvgaTrack = /** @class */ (function (_super) {
    __extends(SvgaTrack, _super);
    function SvgaTrack(obj, frames) {
        var _this = _super.call(this) || this;
        _this.obj = obj;
        _this.frames = frames;
        _this._instanceType = "SvgaTrack";
        return _this;
    }
    /**
     * 这里用的帧数
     * @param time 帧小数
     */
    SvgaTrack.prototype.setValue = function (time) {
        //处理time
        time = Math.round(clamp(time, 0, this.frames.length - 1));
        //找对应数据
        var frame = this.frames[time], sprite = this.obj;
        //layout不晓得干嘛用，暂不管
        if (frame.alpha < 0.05) {
            sprite.alpha = 0;
        }
        else {
            sprite.alpha = frame.alpha;
            //先判断transform是否相等
            if (!Matrix.isEqual(sprite.transform.localMatrix, frame.transform)) {
                sprite.transform.localMatrix.copy(frame.transform);
                sprite.transform._parentID = -1;
            }
            //遮罩
            if (frame.maskPath) {
                //记录一个
                if (!sprite["cusMask"])
                    sprite["cusMask"] = new Shape();
                //没遮罩加上
                if (!sprite.mask)
                    sprite.mask = sprite.addChild(sprite["cusMask"]);
                var mask = sprite.mask;
                drawBezierShape(mask, frame.maskPath);
            }
            else if (sprite.mask) {
                sprite.removeChild(sprite.mask);
                sprite.mask = null;
            }
        }
    };
    SvgaTrack.prototype.resetValue = function () {
        this.setValue(0);
    };
    SvgaTrack.prototype.destroy = function () {
        this.obj = null;
    };
    return SvgaTrack;
}(HashObject));
function drawBezierShape(mask, data, useStyle) {
    if (mask === void 0) { mask = new Shape; }
    if (useStyle === void 0) { useStyle = false; }
    mask.clear();
    var styles = data._styles;
    if (useStyle && styles) { //待测试，两个都有的时候是否能正常绘制，毕竟都执行了beginPath
        if (styles.stroke) {
            mask.beginStroke(rgb2hex$1(styles.stroke), styles.strokeWidth || undefined, styles.lineCap || undefined, styles.lineJoin || undefined, styles.miterLimit || undefined, styles.stroke[3]);
        }
        if (styles.fill) {
            mask.beginFill(rgb2hex$1(styles.fill), styles.fill[3]);
        }
        // if (styles && styles.lineDash) {
        //     ctx.setLineDash(styles.lineDash);
        // }
    }
    else {
        //简单绘制
        mask.beginFill();
    }
    //会用到的，再说TODO
    if (data._transform) {
        //用于修改所有路径的矩阵数据
        mask.transform.localMatrix.copy(data._transform);
        mask.transform._parentID = -1;
    }
    var currentPoint = { x: 0, y: 0, x1: 0, y1: 0, x2: 0, y2: 0 };
    var validMethods = 'MLHVCSQRZmlhvcsqrz';
    var d = data._d.replace(/([a-zA-Z])/g, '|||$1 ').replace(/,/g, ' ');
    d.split('|||').forEach(function (segment) {
        if (segment.length == 0)
            return;
        var firstLetter = segment.substr(0, 1);
        if (validMethods.indexOf(firstLetter) >= 0) {
            var args = segment.substr(1).trim().split(" ");
            switch (firstLetter) {
                case 'M':
                    currentPoint.x = Number(args[0]);
                    currentPoint.y = Number(args[1]);
                    mask.moveTo(currentPoint.x, currentPoint.y);
                    break;
                case 'm':
                    currentPoint.x += Number(args[0]);
                    currentPoint.y += Number(args[1]);
                    mask.moveTo(currentPoint.x, currentPoint.y);
                    break;
                case 'L':
                    currentPoint.x = Number(args[0]);
                    currentPoint.y = Number(args[1]);
                    mask.lineTo(currentPoint.x, currentPoint.y);
                    break;
                case 'l':
                    currentPoint.x += Number(args[0]);
                    currentPoint.y += Number(args[1]);
                    mask.lineTo(currentPoint.x, currentPoint.y);
                    break;
                case 'H':
                    currentPoint.x = Number(args[0]);
                    mask.lineTo(currentPoint.x, currentPoint.y);
                    break;
                case 'h':
                    currentPoint.x += Number(args[0]);
                    mask.lineTo(currentPoint.x, currentPoint.y);
                    break;
                case 'V':
                    currentPoint.y = Number(args[0]);
                    mask.lineTo(currentPoint.x, currentPoint.y);
                    break;
                case 'v':
                    currentPoint.y += Number(args[0]);
                    mask.lineTo(currentPoint.x, currentPoint.y);
                    break;
                case 'C':
                    currentPoint.x1 = Number(args[0]);
                    currentPoint.y1 = Number(args[1]);
                    currentPoint.x2 = Number(args[2]);
                    currentPoint.y2 = Number(args[3]);
                    currentPoint.x = Number(args[4]);
                    currentPoint.y = Number(args[5]);
                    mask.bezierCurveTo(currentPoint.x1, currentPoint.y1, currentPoint.x2, currentPoint.y2, currentPoint.x, currentPoint.y);
                    break;
                case 'c':
                    currentPoint.x1 = currentPoint.x + Number(args[0]);
                    currentPoint.y1 = currentPoint.y + Number(args[1]);
                    currentPoint.x2 = currentPoint.x + Number(args[2]);
                    currentPoint.y2 = currentPoint.y + Number(args[3]);
                    currentPoint.x += Number(args[4]);
                    currentPoint.y += Number(args[5]);
                    mask.bezierCurveTo(currentPoint.x1, currentPoint.y1, currentPoint.x2, currentPoint.y2, currentPoint.x, currentPoint.y);
                    break;
                case 'S':
                    if (currentPoint.x1 && currentPoint.y1 && currentPoint.x2 && currentPoint.y2) {
                        currentPoint.x1 = currentPoint.x - currentPoint.x2 + currentPoint.x;
                        currentPoint.y1 = currentPoint.y - currentPoint.y2 + currentPoint.y;
                        currentPoint.x2 = Number(args[0]);
                        currentPoint.y2 = Number(args[1]);
                        currentPoint.x = Number(args[2]);
                        currentPoint.y = Number(args[3]);
                        mask.bezierCurveTo(currentPoint.x1, currentPoint.y1, currentPoint.x2, currentPoint.y2, currentPoint.x, currentPoint.y);
                    }
                    else {
                        currentPoint.x1 = Number(args[0]);
                        currentPoint.y1 = Number(args[1]);
                        currentPoint.x = Number(args[2]);
                        currentPoint.y = Number(args[3]);
                        mask.quadraticCurveTo(currentPoint.x1, currentPoint.y1, currentPoint.x, currentPoint.y);
                    }
                    break;
                case 's':
                    if (currentPoint.x1 && currentPoint.y1 && currentPoint.x2 && currentPoint.y2) {
                        currentPoint.x1 = currentPoint.x - currentPoint.x2 + currentPoint.x;
                        currentPoint.y1 = currentPoint.y - currentPoint.y2 + currentPoint.y;
                        currentPoint.x2 = currentPoint.x + Number(args[0]);
                        currentPoint.y2 = currentPoint.y + Number(args[1]);
                        currentPoint.x += Number(args[2]);
                        currentPoint.y += Number(args[3]);
                        mask.bezierCurveTo(currentPoint.x1, currentPoint.y1, currentPoint.x2, currentPoint.y2, currentPoint.x, currentPoint.y);
                    }
                    else {
                        currentPoint.x1 = currentPoint.x + Number(args[0]);
                        currentPoint.y1 = currentPoint.y + Number(args[1]);
                        currentPoint.x += Number(args[2]);
                        currentPoint.y += Number(args[3]);
                        mask.quadraticCurveTo(currentPoint.x1, currentPoint.y1, currentPoint.x, currentPoint.y);
                    }
                    break;
                case 'Q':
                    currentPoint.x1 = Number(args[0]);
                    currentPoint.y1 = Number(args[1]);
                    currentPoint.x = Number(args[2]);
                    currentPoint.y = Number(args[3]);
                    mask.quadraticCurveTo(currentPoint.x1, currentPoint.y1, currentPoint.x, currentPoint.y);
                    break;
                case 'q':
                    currentPoint.x1 = currentPoint.x + Number(args[0]);
                    currentPoint.y1 = currentPoint.y + Number(args[1]);
                    currentPoint.x += Number(args[2]);
                    currentPoint.y += Number(args[3]);
                    mask.quadraticCurveTo(currentPoint.x1, currentPoint.y1, currentPoint.x, currentPoint.y);
                    break;
                case 'A':
                    break;
                case 'a':
                    break;
                case 'Z':
                case 'z':
                    mask.closePath();
                    break;
            }
        }
    });
    if (useStyle && styles) { //待测试，两者是否都能执行
        if (styles.fill)
            mask.endFill();
        if (styles.stroke)
            mask.endStroke();
    }
    else {
        //简单，直接绘制
        mask.endFill();
    }
    //返回
    return mask;
}

var getBezierEasing = (function () {
    /**
     * BezierEasing - use bezier curve for transition easing function
     * by Gaëtan Renaudeau 2014 - 2015 – MIT License
     *
     * Credits: is based on Firefox's nsSMILKeySpline.cpp
     * Usage:
     * var spline = BezierEasing([ 0.25, 0.1, 0.25, 1.0 ])
     * spline.get(x) => returns the easing value | x must be in [0, 1] range
     *
     */
    var beziers = {};
    function getBezierEasing(a, b, c, d, nm) {
        var str = nm || ('bez_' + a + '_' + b + '_' + c + '_' + d).replace(/\./g, 'p');
        if (beziers[str]) {
            return beziers[str];
        }
        var bezEasing = new BezierEasing([a, b, c, d]);
        beziers[str] = bezEasing;
        return bezEasing;
    }
    // These values are established by empiricism with tests (tradeoff: performance VS precision)
    var NEWTON_ITERATIONS = 4;
    var NEWTON_MIN_SLOPE = 0.001;
    var SUBDIVISION_PRECISION = 0.0000001;
    var SUBDIVISION_MAX_ITERATIONS = 10;
    var kSplineTableSize = 11;
    var kSampleStepSize = 1.0 / (kSplineTableSize - 1.0);
    var float32ArraySupported = typeof Float32Array === "function";
    function A(aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; }
    function B(aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; }
    function C(aA1) { return 3.0 * aA1; }
    // Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
    function calcBezier(aT, aA1, aA2) {
        return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT;
    }
    // Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
    function getSlope(aT, aA1, aA2) {
        return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1);
    }
    function binarySubdivide(aX, aA, aB, mX1, mX2) {
        var currentX, currentT, i = 0;
        do {
            currentT = aA + (aB - aA) / 2.0;
            currentX = calcBezier(currentT, mX1, mX2) - aX;
            if (currentX > 0.0) {
                aB = currentT;
            }
            else {
                aA = currentT;
            }
        } while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS);
        return currentT;
    }
    function newtonRaphsonIterate(aX, aGuessT, mX1, mX2) {
        for (var i = 0; i < NEWTON_ITERATIONS; ++i) {
            var currentSlope = getSlope(aGuessT, mX1, mX2);
            if (currentSlope === 0.0)
                return aGuessT;
            var currentX = calcBezier(aGuessT, mX1, mX2) - aX;
            aGuessT -= currentX / currentSlope;
        }
        return aGuessT;
    }
    /**
     * points is an array of [ mX1, mY1, mX2, mY2 ]
     */
    function BezierEasing(points) {
        this._p = points;
        this._mSampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize);
        this._precomputed = false;
        this.get = this.get.bind(this);
    }
    BezierEasing.prototype = {
        get: function (x) {
            var mX1 = this._p[0], mY1 = this._p[1], mX2 = this._p[2], mY2 = this._p[3];
            if (!this._precomputed)
                this._precompute();
            if (mX1 === mY1 && mX2 === mY2)
                return x; // linear
            // Because JavaScript number are imprecise, we should guarantee the extremes are right.
            if (x === 0)
                return 0;
            if (x === 1)
                return 1;
            return calcBezier(this._getTForX(x), mY1, mY2);
        },
        // Private part
        _precompute: function () {
            var mX1 = this._p[0], mY1 = this._p[1], mX2 = this._p[2], mY2 = this._p[3];
            this._precomputed = true;
            if (mX1 !== mY1 || mX2 !== mY2)
                this._calcSampleValues();
        },
        _calcSampleValues: function () {
            var mX1 = this._p[0], mX2 = this._p[2];
            for (var i = 0; i < kSplineTableSize; ++i) {
                this._mSampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2);
            }
        },
        /**
         * getTForX chose the fastest heuristic to determine the percentage value precisely from a given X projection.
         */
        _getTForX: function (aX) {
            var mX1 = this._p[0], mX2 = this._p[2], mSampleValues = this._mSampleValues;
            var intervalStart = 0.0;
            var currentSample = 1;
            var lastSample = kSplineTableSize - 1;
            for (; currentSample !== lastSample && mSampleValues[currentSample] <= aX; ++currentSample) {
                intervalStart += kSampleStepSize;
            }
            --currentSample;
            // Interpolate to provide an initial guess for t
            var dist = (aX - mSampleValues[currentSample]) / (mSampleValues[currentSample + 1] - mSampleValues[currentSample]);
            var guessForT = intervalStart + dist * kSampleStepSize;
            var initialSlope = getSlope(guessForT, mX1, mX2);
            if (initialSlope >= NEWTON_MIN_SLOPE) {
                return newtonRaphsonIterate(aX, guessForT, mX1, mX2);
            }
            else if (initialSlope === 0.0) {
                return guessForT;
            }
            else {
                return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2);
            }
        }
    };
    return getBezierEasing;
}());

function buildBezierProp(pt1, pt2, pt3, pt4, startIndex, endIndex, time, fnc) {
    var bezierData = buildBezierData(pt1, pt2, pt3, pt4);
    var perc = fnc((time - startIndex) / (endIndex - startIndex));
    var distanceInLine = bezierData.segmentLength * perc;
    if (perc == 0)
        return bezierData.points[0].point;
    if (perc == 1)
        return bezierData.points[bezierData.points.length - 1].point;
    //找最近的点
    return findNearest(distanceInLine, bezierData.points);
}
function findNearest(distanceInLine, bezierDataPoints) {
    for (var i = 0; i < bezierDataPoints.length; i++) {
        var preLength = bezierDataPoints[i].preLength;
        if (distanceInLine < preLength) { //前一帧后当前帧做补间，且i肯定不会为0，因为distanceInLine不会小于0；
            var segmentPerc = (distanceInLine - bezierDataPoints[i - 1].preLength) / bezierDataPoints[i].partialLength;
            var kLen = bezierDataPoints[i - 1].point.length;
            var newValue = [];
            for (var k = 0; k < kLen; k += 1) {
                newValue[k] = bezierDataPoints[i - 1].point[k] + (bezierDataPoints[i].point[k] - bezierDataPoints[i - 1].point[k]) * segmentPerc;
            }
            return newValue; //取补间
        }
    }
    //没有返回最后一个
    return bezierDataPoints[bezierDataPoints.length - 1].point;
}
var storedData = {};
function buildBezierData(pt1, pt2, pt3, pt4) {
    var bezierName = (pt1[0] + '_' + pt1[1] + '_' + pt2[0] + '_' + pt2[1] + '_' + pt3[0] + '_' + pt3[1] + '_' + pt4[0] + '_' + pt4[1]).replace(/\./g, 'p');
    if (!storedData[bezierName]) {
        var curveSegments = 150; //defaultCurveSegments;
        var k, i, len;
        var ptCoord, perc, addedLength = 0;
        var ptDistance;
        var point, lastPoint = null;
        if (pt1.length === 2 && (pt1[0] != pt2[0] || pt1[1] != pt2[1]) && pointOnLine2D(pt1[0], pt1[1], pt2[0], pt2[1], pt1[0] + pt3[0], pt1[1] + pt3[1]) && pointOnLine2D(pt1[0], pt1[1], pt2[0], pt2[1], pt2[0] + pt4[0], pt2[1] + pt4[1])) {
            curveSegments = 2;
            //这种情况只会生成两个点
        }
        var bezierData = {
            segmentLength: 0,
            points: new Array(curveSegments)
        };
        len = pt3.length;
        for (k = 0; k < curveSegments; k += 1) {
            point = new Array(len);
            perc = k / (curveSegments - 1);
            ptDistance = 0;
            for (i = 0; i < len; i += 1) {
                ptCoord = Math.pow(1 - perc, 3) * pt1[i] + 3 * Math.pow(1 - perc, 2) * perc * (pt1[i] + pt3[i]) + 3 * (1 - perc) * Math.pow(perc, 2) * (pt2[i] + pt4[i]) + Math.pow(perc, 3) * pt2[i];
                point[i] = ptCoord;
                if (lastPoint !== null) {
                    ptDistance += Math.pow(point[i] - lastPoint[i], 2);
                }
            }
            ptDistance = Math.sqrt(ptDistance);
            addedLength += ptDistance;
            bezierData.points[k] = {
                partialLength: ptDistance,
                preLength: addedLength,
                point: point
            };
            lastPoint = point;
        }
        bezierData.segmentLength = addedLength;
        storedData[bezierName] = bezierData;
    }
    return storedData[bezierName];
}
function pointOnLine2D(x1, y1, x2, y2, x3, y3) {
    var det1 = (x1 * y2) + (y1 * x3) + (x2 * y3) - (x3 * y2) - (y3 * x1) - (x2 * y1);
    return det1 > -0.001 && det1 < 0.001;
}

var Lottie = /** @class */ (function (_super) {
    __extends(Lottie, _super);
    function Lottie(data) {
        var _this = _super.call(this, data) || this;
        _this._instanceType = "Lottie";
        return _this;
    }
    Object.defineProperty(Lottie.prototype, "totalTime", {
        /**
         * 总时间，秒计
         */
        get: function () {
            if (!this.rawData)
                return 0;
            var _a = this.rawData, op = _a.op, ip = _a.ip;
            return (op - ip) * (1 / this.fps);
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Lottie.prototype, "totalFrames", {
        /**
         * 总帧数
         */
        get: function () {
            if (!this.rawData)
                return 0;
            var _a = this.rawData, op = _a.op, ip = _a.ip;
            return op - ip;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Lottie.prototype, "videoWidth", {
        /**
         * 动画显示宽度
         */
        get: function () {
            return this.rawData && this.rawData.w || 0;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Lottie.prototype, "videoHeight", {
        /**
         * 动画显示高度
         */
        get: function () {
            return this.rawData && this.rawData.h || 0;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Lottie.prototype, "fps", {
        /**
         * 重写
         * 每秒刷新帧数，没设置过直接用数据里的
         */
        get: function () {
            //没设置过就用数据里的
            return this._fps || this.rawData && this.rawData.fr || null;
        },
        set: function (v) {
            this._fps = v;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 初始化方法
     * @param data
     * @returns
     */
    Lottie.prototype.init = function (data) {
        if (!data || data == this.rawData)
            return;
        this.rawData = data;
        //名字
        this.name = data.nm;
        //初始化图片 有assets但无textures
        if (data.assets && !data.textures) {
            data.textures = {};
            data.assets.forEach(function (a) {
                if (a.layers) { //合成嵌套的情况
                    data.compositions = data.compositions || {};
                    data.compositions[a.id] = a.layers;
                    return;
                }
                var imgTag = createImage();
                imgTag.src = a.p;
                data.textures[a.id] = new Texture(new BaseTexture(imgTag));
            });
        }
        //原先有的，先销毁
        this.lottieContainer && this.lottieContainer.destroy();
        //初始化一个容器；
        this.lottieContainer = this.addChild(new LottieContainer());
        //生成时间轴
        var tracks = createLottieTracks(this.lottieContainer, data.layers, data.ip, data.textures, data.compositions);
        //初始值设置下
        tracks.forEach(function (t) {
            //初始值重置下
            t.resetValue();
            //表达式的加一个帧率，其实是最好createLottieTracks传入，再说了
            if (t.instanceType == "LottieExpressionTrack") {
                t.frameRate = data.fr;
            }
        });
        //合成所有时间轴
        if (!this.animationClip) {
            this.animationClip = new AnimationClip(tracks, this.totalFrames);
        }
        else {
            this.animationClip.init(tracks, this.totalFrames);
        }
        //数据更新
        this._onRawDataUpdate();
    };
    /**
     * 是否使用Graphics矢量作为遮罩，默认false不使用，即使用Shape
     * 使用Shape时在webgl模式下会新建一张离屏canvas，增加内存
     * 有内存要求时可尝试设置为true，
     */
    Lottie.useGraphicsMask = false;
    return Lottie;
}(AnimationNode));
var ILottieLoopType;
(function (ILottieLoopType) {
    ILottieLoopType["pingpong"] = "pingpong";
    ILottieLoopType["cycle"] = "cycle";
})(ILottieLoopType || (ILottieLoopType = {}));
/**
 * 内部使用,不对外导出,这里track的时间统统是帧时间,所以对于AnimationClip的update传的时间做换算
 * 注意lottie的透明度是不影响子级的
 */
var LottieBaseTrack = /** @class */ (function (_super) {
    __extends(LottieBaseTrack, _super);
    function LottieBaseTrack(obj, type, times, loop, ip, //偏移
    xy) {
        if (ip === void 0) { ip = 0; }
        if (xy === void 0) { xy = null; }
        var _this = _super.call(this) || this;
        _this.obj = obj;
        _this.type = type;
        _this.times = times;
        _this.loop = loop;
        _this.ip = ip;
        _this.xy = xy;
        _this._instanceType = "LottieBaseTrack";
        return _this;
    }
    /**
     * 子类重写
     * @param time
     */
    LottieBaseTrack.prototype.setValue = function (time) {
        time -= this.ip;
        // if (!this.obj.visible) return
        setValue(this.obj, this.cacValue(time), this.type, this.xy);
        // var value = this.cacValue(time);
        // switch (this.type) {
        //     case "r":
        //         this.obj.rotation = value[0];
        //         break;
        //     case "o":
        //         this.obj.alpha = value[0] / 100;
        //         break;
        //     case "s":
        //         this.obj.scale.set(value[0] / 100, value[1] / 100);
        //         break;
        //     case "p":
        //         this.obj.position.set(value[0] - this.obj.anchorX, value[1] - this.obj.anchorY);
        //         break;
        // }
    };
    /**
     *
     * @param time
     * @returns
     */
    LottieBaseTrack.prototype.cacValue = function (time) {
        //计算真实时间，因为部分又表达式的
        if (this.loop && this.loop.loopInOrOut) {
            time = (this.loop.loopInOrOut == 1 ? loopIn : loopOut)(this.loop.type, this.loop.duration, this.times, time);
        }
        if (time <= this.times[0].t)
            return this.times[0].s;
        if (time >= this.times[this.times.length - 1].t)
            return this.times[this.times.length - 1].s || this.times[this.times.length - 2].e;
        //其他的计算补间了要，找前后两个索引
        var after = this.findIndex(time);
        var before = after - 1;
        var da = this.times[after];
        var db = this.times[before];
        var beforeValue = db.s, afterValue = da.s || db.e;
        var value;
        //有路径的
        if (db.to) {
            db.fnc = db.fnc || getBezierEasing(db.o.x, db.o.y, db.i.x, db.i.y).get;
            value = buildBezierProp(beforeValue, afterValue, db.to, db.ti, db.t, da.t, time, db.fnc);
        }
        //有h的
        else if (db.h === 1) {
            value = beforeValue;
        }
        else {
            db.fnc = db.fnc || generateFuncs(db.o, db.i, beforeValue.length);
            var newValue = [], perc, delta = da.t - db.t;
            for (var i = 0; i < beforeValue.length; i += 1) {
                if (time >= da.t) {
                    perc = 1;
                }
                else if (time < db.t) {
                    perc = 0;
                }
                else {
                    if (!db.fnc) { //线性
                        perc = (time - db.t) / delta;
                    }
                    else if (db.fnc.constructor === Array) {
                        perc = db.fnc[i]((time - db.t) / delta);
                    }
                    else {
                        perc = db.fnc((time - db.t) / delta);
                    }
                }
                newValue[i] = beforeValue[i] + (afterValue[i] - beforeValue[i]) * perc;
            }
            value = newValue;
        }
        return value;
    };
    /**
     * 首尾已判断，得到后一位索引
     * @param times
     * @param time
     * @returns
     */
    LottieBaseTrack.prototype.findIndex = function (time) {
        var low = 0;
        var high = this.times.length - 2;
        if (high == 0)
            return 1;
        var current = high >>> 1;
        while (true) {
            if (this.times[current + 1].t <= time)
                low = current + 1;
            else
                high = current;
            if (low == high)
                return low + 1;
            current = (low + high) >>> 1;
        }
    };
    LottieBaseTrack.prototype.resetValue = function () {
        this.setValue(0);
    };
    LottieBaseTrack.prototype.destroy = function () {
        this.obj = null;
    };
    return LottieBaseTrack;
}(HashObject));
/**
 * 部件的出场时间,就是个范围,
 * 每个对象都有,优先判断
 */
var LottieVisibleTrack = /** @class */ (function (_super) {
    __extends(LottieVisibleTrack, _super);
    function LottieVisibleTrack(obj, inTime, outTime, startTime, ip) {
        if (ip === void 0) { ip = 0; }
        var _this = _super.call(this) || this;
        _this.obj = obj;
        _this.inTime = inTime;
        _this.outTime = outTime;
        _this.startTime = startTime;
        _this.ip = ip;
        _this._instanceType = "LottieVisibleTrack";
        return _this;
    }
    /**
     * @param time
     */
    LottieVisibleTrack.prototype.setValue = function (time) {
        time -= this.ip;
        // this.obj.visible = this.inTime <= time && this.outTime >= time
        this.obj.visible = this.inTime <= time && this.outTime > time; //out不能等，否则重合
    };
    LottieVisibleTrack.prototype.resetValue = function () {
        this.setValue(0);
    };
    LottieVisibleTrack.prototype.destroy = function () {
        this.obj = null;
    };
    return LottieVisibleTrack;
}(HashObject));
/**
 * 纯表达式的时间轴
 */
var LottieExpressionTrack = /** @class */ (function (_super) {
    __extends(LottieExpressionTrack, _super);
    function LottieExpressionTrack(obj, type, expression, origionValue, ip) {
        if (ip === void 0) { ip = 0; }
        var _this = _super.call(this) || this;
        _this.obj = obj;
        _this.type = type;
        _this.expression = expression;
        _this.origionValue = origionValue;
        _this.ip = ip;
        _this._instanceType = "LottieExpressionTrack";
        var e = _this.expression.split("$bm_rt = ")[1]; //取后面的//前面的var $bm_rt;\n$bm_rt = 没用
        _this.node = parseExpression(e);
        return _this;
        // console.log(this.node)
    }
    /**
     * @param time
     */
    LottieExpressionTrack.prototype.setValue = function (time) {
        time -= this.ip;
        time /= this.frameRate; //注意修改FPS时需要遍历该类时间轴
        //   if(this.type=="o")  console.log(runExpressionNode(this.node, time))
        setValue(this.obj, runExpressionNode(this.node, time), this.type);
    };
    LottieExpressionTrack.prototype.resetValue = function () {
        setValue(this.obj, this.origionValue, this.type);
    };
    LottieExpressionTrack.prototype.destroy = function () {
        this.obj = null;
    };
    return LottieExpressionTrack;
}(HashObject));
function loopOut(type, duration, keyframes, currentFrame) {
    var lastKeyFrame = keyframes[keyframes.length - 1].t;
    if (currentFrame <= lastKeyFrame)
        return currentFrame;
    if (!duration || duration > keyframes.length - 1) {
        duration = keyframes.length - 1;
    }
    var firstKeyFrame = keyframes[keyframes.length - 1 - duration].t;
    var cycleDuration = lastKeyFrame - firstKeyFrame;
    // var i, len, ret;
    if (type === 'pingpong') {
        var iterations = Math.floor((currentFrame - firstKeyFrame) / cycleDuration);
        if (iterations % 2 !== 0) {
            return cycleDuration - (currentFrame - firstKeyFrame) % cycleDuration + firstKeyFrame;
        }
    }
    //其他的再说
    // else if(){
    // }
    return (currentFrame - firstKeyFrame) % cycleDuration + firstKeyFrame;
}
//给出时间就行,自行判断是否计算，根据
function loopIn(type, duration, keyframes, currentFrame) {
    var firstKeyFrame = keyframes[0].t;
    if (currentFrame >= firstKeyFrame)
        return currentFrame;
    //0时取全部
    if (!duration || duration > keyframes.length - 1) {
        duration = keyframes.length - 1;
    }
    var lastKeyFrame = keyframes[duration].t;
    var cycleDuration = lastKeyFrame - firstKeyFrame;
    // var i, len, ret;
    if (type === ILottieLoopType.pingpong) {
        var iterations = Math.floor((firstKeyFrame - currentFrame) / cycleDuration);
        if (iterations % 2 === 0) {
            return (firstKeyFrame - currentFrame) % cycleDuration + firstKeyFrame;
        }
    }
    //其他的再说
    // else if(){
    // }
    return cycleDuration - (firstKeyFrame - currentFrame) % cycleDuration + firstKeyFrame;
}
function generateFuncs(outV, inV, len) {
    //无参数时直接返回null
    if (!outV || !inV)
        return null;
    var outX, outY, inX, inY;
    if (outV.x.constructor === Array) {
        var fncts = [];
        for (var i = 0; i < len; i++) {
            outX = (typeof outV.x[i] === 'undefined') ? outV.x[0] : outV.x[i];
            outY = (typeof outV.y[i] === 'undefined') ? outV.y[0] : outV.y[i];
            inX = (typeof inV.x[i] === 'undefined') ? inV.x[0] : inV.x[i];
            inY = (typeof inV.y[i] === 'undefined') ? inV.y[0] : inV.y[i];
            fncts[i] = getBezierEasing(outX, outY, inX, inY).get;
        }
        return fncts;
    }
    else {
        outX = outV.x;
        outY = outV.y;
        inX = inV.x;
        inY = inV.y;
        return getBezierEasing(outX, outY, inX, inY).get;
    }
}
function getLoopData(x) {
    if (!x)
        return null;
    //取数字
    var rr = +x.replace(/[^0-9]/ig, "");
    var loopInOrOut = 0;
    if (x.indexOf("loopOut") >= 0) {
        loopInOrOut = 2;
    }
    else if (x.indexOf("loopIn") >= 0) {
        loopInOrOut = 1;
    }
    var type;
    if (x.indexOf("pingpong") >= 0) {
        type = ILottieLoopType.pingpong;
    }
    else if (x.indexOf("cycle") >= 0) {
        type = ILottieLoopType.cycle;
    }
    return { loopInOrOut: loopInOrOut, type: type, duration: rr };
}
function setValue(obj, value, type, xy) {
    //转下数字的为数组
    if (typeof value == "number")
        value = [value];
    switch (type) {
        case "r":
            obj.rotation = value[0];
            break;
        case "o":
            obj.alpha = value[0] / 100;
            break;
        case "s":
            if (xy) {
                obj[xy == "x" ? "scaleX" : "scaleY"] = value[0] / 100;
            }
            else {
                obj.scale.set(value[0] / 100, value[1] / 100);
            }
            break;
        case "p":
            if (xy) {
                obj[xy] = value[0] - (xy == "x" ? obj.anchorX : obj.anchorY);
            }
            else {
                obj.position.set(value[0] - obj.anchorX, value[1] - obj.anchorY);
            }
            break;
    }
}
/**
 * 一个子级完全平铺，但是子级却存在父级id记录的容器类，lottie会继承自他，还有合成的也继承自他
 */
var LottieContainer = /** @class */ (function (_super) {
    __extends(LottieContainer, _super);
    function LottieContainer() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    /**
     * 对所有的进行刷新，，根据cParent进行迭代刷新
     * 层级有问题，只能平铺，手动计算矩阵
     * 因为要平铺，所以记录cParent和ind  从1开始，也许只需要+1就行，还是用ind记录查找吧
     * 遍历找
     */
    LottieContainer.prototype.updateTransform = function () {
        var _this = this;
        //super不行，到时查
        this.displayObjectUpdateTransform();
        this.children.forEach(function (c) {
            _this._recursivePostUpdateTransformAA(c);
        });
        this.children.forEach(function (c) {
            c._mark = false;
        });
    };
    LottieContainer.prototype.findChildByInd = function (ind) {
        for (var i = 0; i < this.children.length; i++) {
            if (this.children[i]._ind === ind)
                return this.children[i];
        }
        return null;
    };
    LottieContainer.prototype._recursivePostUpdateTransformAA = function (c) {
        if (c._isLottieLayer && c._parentId) {
            //ind从1开始，所以不用考虑0，且不应该存在 p没有的情况
            var p = this.findChildByInd(c._parentId);
            this._recursivePostUpdateTransformAA(p);
            if (!c._mark) {
                c._mark = true;
                // c.transform.updateWorldMatrix(p.transform);
                //用临时父级的方式，否则合成嵌套的子级不会更新
                var cacheParent = c.parent;
                c.parent = p;
                c.updateTransform();
                c.parent = cacheParent;
                //透明度单独计算，不跟p保持，这个到时要测试下，可以需要向上递归取透明度才是对的
                c._worldAlpha = c.alpha * c.parent._worldAlpha;
            }
        }
        //直接进行tans
        else if (!c._mark) {
            c.updateTransform(); //alpha跟父级有关，这里透明度也一样
            c._mark = true;
        }
    };
    return LottieContainer;
}(Container));
/**
 * 递归创建lottie时间轴，
 * @param root
 * @param layers
 * @param offset
 * @param textures
 * @param compositions
 * @param tracks
 * @returns
 */
function createLottieTracks(root, layers, offset, textures, compositions, tracks) {
    if (tracks === void 0) { tracks = []; }
    var _loop_1 = function () {
        var layer = layers[i];
        var ty = layer.ty, refId = layer.refId, ks = layer.ks, parent = layer.parent, ind = layer.ind, ip = layer.ip, op = layer.op, st = layer.st, hasMask = layer.hasMask, masksProperties = layer.masksProperties;
        var c;
        //如果存在组件嵌套
        if (ty == 0 && compositions) {
            c = root.addChild(new LottieContainer());
            //递归创建，宽高和名字暂时不需要，
            createLottieTracks(c, compositions[refId], offset + ip, textures, compositions, tracks);
        }
        //矢量，暂时先用Shape，后续矢量类型都确定再考虑加入Graphics，还有点问题，尽量少用吧，tr的处理便宜貌似有一点误差，换成Graphic貌似也一样
        else if (ty == 4 && layer["shapes"]) {
            c = root.addChild(createShape(layer["shapes"]));
            // console.log(c)
            //@ts-ignore
            // document.body.appendChild(c.canvas)
        }
        //图片图层，不能判断2.因为有部分是Container
        else {
            c = root.addChild(new Sprite(refId ?
                textures && textures[refId] ||
                    TextureCache[refId] ||
                    TextureCache[refId + ".png"] : null));
        }
        //遮罩数据，遮罩矩阵和c一致，所以加在c里面
        if (hasMask && masksProperties && masksProperties.length) {
            c.mask = c.addChild(createLottieMask(masksProperties, layer.w, layer.h));
        }
        //标记下
        c._isLottieLayer = true;
        //记录一下数据，查找父级的时候有用
        c._ind = ind, c._parentId = parent;
        //处理下锚点，基本不会有锚点动画
        ad = typeof ks.a.k[0] == "number" ? ks.a.k : ks.a.k[0].s;
        c.anchor.set(ad[0], ad[1]);
        //加显示隐藏的
        tracks.push(new LottieVisibleTrack(c, ip, op, st, offset));
        ["o", "r", "p", "s"].forEach(function (type) {
            var k = ks[type].k;
            var expression = ks[type].x;
            //考虑x和y分开的情况，不会有加减
            if (!k) {
                //以防万一，判断下r和o
                if (!ks[type].s || type == "r" || type == "o")
                    return;
                //这时候x就是维度了，不再是表达式
                ["x", "y"].forEach(function (xy) {
                    var kk = ks[type][xy].k;
                    var eexpression = ks[type][xy].x;
                    if (kk.length) {
                        tracks.push(new LottieBaseTrack(c, type, kk, getLoopData(eexpression), offset, xy));
                    }
                    else {
                        setValue(c, kk, type, xy);
                        //不管加减表达式
                    }
                });
                return;
            }
            //@ts-ignore
            if (((type == "o" || type == "r") && k.length) || //透明度和旋转，k有长度就是关键帧，
                ((type == "s" || type == "p") && typeof k[0] != "number")) { //透明度和旋转，k有长度就是关键帧，位置和缩放得k的元素里不是number
                tracks.push(new LottieBaseTrack(c, type, k, getLoopData(expression), offset));
            }
            else {
                //没有关键帧的设置下初始值
                setValue(c, k, type);
                //表达式判断，但是不管loop那些表达式，因为已经进BaseTrack了的，也不管位移和缩放的先
                if (expression && expression.indexOf("loop") == -1 && type !== "s" && type !== "p") {
                    tracks.push(new LottieExpressionTrack(c, type, expression, k, offset));
                }
            }
        });
    };
    var ad;
    for (var i = layers.length - 1; i >= 0; i--) {
        _loop_1();
    }
    return tracks;
}
/**
 * 生成lottie的遮罩矢量
 * @param masksProperties
 * @param w
 * @param h
 * @returns
 */
function createLottieMask(masksProperties, w, h) {
    var mask = Lottie.useGraphicsMask ? new Graphics() : new Shape();
    mask.beginFill();
    masksProperties.forEach(function (m) {
        if (m.mode !== 'n') {
            if (m.inv) {
                mask.moveTo(0, 0);
                mask.lineTo(w, 0);
                mask.lineTo(w, h);
                mask.lineTo(0, h);
                mask.lineTo(0, 0);
            }
            var data = m.pt.k;
            mask.moveTo(data.v[0][0], data.v[0][1]);
            var j, jLen = data.v.length;
            for (j = 1; j < jLen; j++) {
                mask.bezierCurveTo(data.o[j - 1][0] + data.v[j - 1][0], data.o[j - 1][1] + data.v[j - 1][1], data.i[j][0] + data.v[j][0], data.i[j][1] + data.v[j][1], data.v[j][0], data.v[j][1]);
            }
            mask.bezierCurveTo(data.o[j - 1][0] + data.v[j - 1][0], data.o[j - 1][1] + data.v[j - 1][1], data.i[0][0] + data.v[0][0], data.i[0][1] + data.v[0][1], data.v[0][0], data.v[0][1]);
            if (data.c) ;
        }
    });
    mask.endFill();
    return mask;
}
//解析表达式，暂时只有一维数据的加减乘除
function parseExpression(source) {
    var pos = 0;
    var word = '';
    var stack = [];
    var node;
    var char;
    while (char = source[pos++]) {
        switch (char) {
            case '(':
                node = { op: word, args: [] };
                word = '';
                stack.push(node);
                break;
            case ')':
                push();
                node = stack[stack.length - 1];
                stack.pop();
                break;
            case ',':
                push();
                break;
            case ' ':
                break;
            default:
                word += char;
        }
    }
    return node;
    function push() {
        var val = word;
        // if (!isNaN(word)) {
        //     val = parseFloat(word)
        // }
        stack[stack.length - 1].args.push(word ? val : node);
        word = '';
    }
}
//四种函数的映射
var expressionFuns = {
    $bm_sum: function (a, b) { return a + b; },
    $bm_sub: function (a, b) { return a - b; },
    $bm_mul: function (a, b) { return a * b; },
    $bm_div: function (a, b) { return a / b; }
};
function runExpressionNode(node, time) {
    return opp(node.op, node.args[0], node.args[1], time);
    function opp(op, a, b, time) {
        if (a.op) {
            a = opp(a.op, a.args[0], a.args[1], time);
        }
        else if (a == "time") {
            a = time;
        }
        if (b.op) {
            b = opp(b.op, b.args[0], b.args[1], time);
        }
        else if (b == "time") {
            b = time;
        }
        return expressionFuns[op](+a, +b);
    }
}
var ShapeType;
(function (ShapeType) {
    //组，1
    ShapeType["gr"] = "gr";
    //fill填充，1
    ShapeType["fl"] = "fl";
    //stroke描边
    ShapeType["st"] = "st";
    //trim,先不管
    ShapeType["tm"] = "tm";
    //transform，1
    ShapeType["tr"] = "tr";
    //ellipse，1
    ShapeType["el"] = "el";
    //star
    ShapeType["sr"] = "sr";
    //shapePath,路径
    ShapeType["sh"] = "sh";
    //rect，矩形，1
    ShapeType["rc"] = "rc";
    //rounded圆角，1
    ShapeType["rd"] = "rd";
    //repeater，
    ShapeType["rp"] = "rp";
    //gradientFill
    ShapeType["gf"] = "gf";
})(ShapeType || (ShapeType = {}));
//创建shape
var tempMatrix$1, fill = true;
var lineCap = {
    1: 'butt',
    2: 'round',
    3: 'square',
};
var lineJoin = {
    1: 'miter',
    2: 'round',
    3: 'bevel',
};
function createShape(shapeDatas, shape) {
    if (shape === void 0) { shape = new Shape(); }
    for (var i = shapeDatas.length - 1; i >= 0; i--) {
        var shapeData = shapeDatas[i];
        var type = shapeData.ty;
        //组的话,继续
        if (type == "gr") {
            createShape(shapeData.it, shape);
            fill ? shape.endFill() : shape.endStroke();
        }
        else { //这些指令的顺序应该不影响，但是Graphics可能就要改了
            if (type == "rc") {
                var _a = shapeData.p, p = _a === void 0 ? { k: [0, 0] } : _a, s = shapeData.s, _b = shapeData.r, r = _b === void 0 ? { k: 0 } : _b;
                var po = tempMatrix$1.transformPoint(p.k[0], p.k[1]); //这里处理有点问题，po.x-5差不多才重合
                shape[r.k ? "drawRoundedRect" : "drawRect"](po.x, po.y, s.k[0], s.k[1], r.k);
            }
            else if (type == "el") {
                var _c = shapeData.p, p = _c === void 0 ? { k: [0, 0] } : _c, s = shapeData.s;
                var po = tempMatrix$1.transformPoint(p.k[0], p.k[1]);
                shape.drawEllipse(po.x, po.y, s.k[0] / 2, s.k[1] / 2);
                // shape.drawCircle(p.k[0], p.k[1], s.k[0]/2)
            }
            else if (type == "fl" || type == "st") {
                //颜色
                var _d = shapeData.c, c = _d === void 0 ? { k: [0, 0, 0, 1] } : _d, _e = shapeData.o, o = _e === void 0 ? { k: 1 } : _e;
                var color = rgb2hex$1([c.k[0], c.k[1], c.k[2]]);
                var alpha = c.k[3] * o.k / 100;
                if (type == "fl") {
                    // shapeData.r   2:evenodd   1:nonzero
                    shape.beginFill(color, alpha);
                    fill = true;
                }
                else {
                    var w = shapeData.w, lc = shapeData.lc, lj = shapeData.lj, ml = shapeData.ml; shapeData.hd; shapeData.d; //hd是否比否，是否执行closePath,d虚线
                    shape.beginStroke(color, w && w.k || 1, lineCap[lc], lineJoin[lj], ml, alpha);
                    fill = false;
                }
            }
            else if (type == "tr") {
                tempMatrix$1 = tempMatrix$1 || new Matrix();
                var _f = shapeData.p, p = _f === void 0 ? { k: [0, 0] } : _f, _g = shapeData.a, a = _g === void 0 ? { k: [0, 0] } : _g, _h = shapeData.s, s = _h === void 0 ? { k: [0, 0] } : _h, _j = shapeData.r, r = _j === void 0 ? { k: 0 } : _j, o = shapeData.o; shapeData.sk; shapeData.sa;
                tempMatrix$1.createBox(p.k[0], p.k[1], s.k[0] / 100, s.k[1] / 100, r.k * RAD_TO_DEG, 0, 0, a.k[0], a.k[1]);
                //影响位置原点，减掉锚点，
                tempMatrix$1.tx -= a.k[0];
                tempMatrix$1.ty -= a.k[1];
                // console.log(tempMatrix.a, tempMatrix.b, tempMatrix.c, tempMatrix.d, tempMatrix.tx, tempMatrix.ty)
                //透明度o，想想咋搞，sk和sa先不管吧
                // console.log(o.k)
                //Shape
                // shape["_command"][shape["_command"].length] = [1, "setTransform", [tempMatrix.a, tempMatrix.b, tempMatrix.c, tempMatrix.d, tempMatrix.tx, tempMatrix.ty]];
            }
        }
    }
    return shape;
}

var Vector3 = /** @class */ (function () {
    function Vector3(x, y, z) {
        if (x === void 0) { x = 0; }
        if (y === void 0) { y = 0; }
        if (z === void 0) { z = 0; }
        this.x = x;
        this.y = y;
        this.z = z;
    }
    Vector3.prototype.set = function (x, y, z) {
        this.x = x;
        this.y = y;
        this.z = z;
        return this;
    };
    Vector3.prototype.copy = function (v) {
        this.x = v.x;
        this.y = v.y;
        this.z = v.z;
        return this;
    };
    Vector3.prototype.clone = function () {
        return new Vector3().copy(this);
    };
    Vector3.prototype.add = function (v) {
        this.x += v.x;
        this.y += v.y;
        this.z += v.z;
        return this;
    };
    Vector3.prototype.addScalar = function (s) {
        this.x += s;
        this.y += s;
        this.z += s;
        return this;
    };
    Vector3.prototype.addVectors = function (a, b) {
        this.x = a.x + b.x;
        this.y = a.y + b.y;
        this.z = a.z + b.z;
        return this;
    };
    Vector3.prototype.addScaledVector = function (v, s) {
        this.x += v.x * s;
        this.y += v.y * s;
        this.z += v.z * s;
        return this;
    };
    Vector3.prototype.sub = function (v) {
        this.x -= v.x;
        this.y -= v.y;
        this.z -= v.z;
        return this;
    };
    Vector3.prototype.subScalar = function (s) {
        this.x -= s;
        this.y -= s;
        this.z -= s;
        return this;
    };
    Vector3.prototype.subVectors = function (a, b) {
        this.x = a.x - b.x;
        this.y = a.y - b.y;
        this.z = a.z - b.z;
        return this;
    };
    Vector3.prototype.multiplyScalar = function (scalar) {
        this.x *= scalar;
        this.y *= scalar;
        this.z *= scalar;
        return this;
    };
    Vector3.prototype.multiplyVectors = function (a, b) {
        this.x = a.x * b.x;
        this.y = a.y * b.y;
        this.z = a.z * b.z;
        return this;
    };
    Vector3.prototype.divide = function (v) {
        this.x /= v.x;
        this.y /= v.y;
        this.z /= v.z;
        return this;
    };
    Vector3.prototype.divideScalar = function (scalar) {
        return this.multiplyScalar(1 / scalar);
    };
    Vector3.prototype.cross = function (v) {
        return this.crossVectors(this, v);
    };
    Vector3.prototype.crossVectors = function (a, b) {
        var ax = a.x, ay = a.y, az = a.z;
        var bx = b.x, by = b.y, bz = b.z;
        this.x = ay * bz - az * by;
        this.y = az * bx - ax * bz;
        this.z = ax * by - ay * bx;
        return this;
    };
    Vector3.prototype.dot = function (v) {
        return this.x * v.x + this.y * v.y + this.z * v.z;
    };
    /**
     * 长度
     */
    Vector3.prototype.length = function () {
        return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
    };
    Vector3.prototype.lengthSq = function () {
        return this.x * this.x + this.y * this.y + this.z * this.z;
    };
    /**
     * 标准化，长度为1
     */
    Vector3.prototype.normalize = function () {
        var scalar = 1 / (this.length() || 1);
        this.x *= scalar;
        this.y *= scalar;
        this.z *= scalar;
        return this;
    };
    Vector3.prototype.distanceTo = function (v) {
        return Math.sqrt(this.distanceToSquared(v));
    };
    Vector3.prototype.distanceToSquared = function (v) {
        var dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;
        return dx * dx + dy * dy + dz * dz;
    };
    Vector3.prototype.min = function (v) {
        this.x = Math.min(this.x, v.x);
        this.y = Math.min(this.y, v.y);
        this.z = Math.min(this.z, v.z);
        return this;
    };
    Vector3.prototype.max = function (v) {
        this.x = Math.max(this.x, v.x);
        this.y = Math.max(this.y, v.y);
        this.z = Math.max(this.z, v.z);
        return this;
    };
    Vector3.prototype.clamp = function (min, max) {
        this.x = Math.max(min.x, Math.min(max.x, this.x));
        this.y = Math.max(min.y, Math.min(max.y, this.y));
        this.z = Math.max(min.z, Math.min(max.z, this.z));
        return this;
    };
    Vector3.prototype.clampScalar = function (minVal, maxVal) {
        return this.clamp(new Vector3(minVal, minVal, minVal), new Vector3(maxVal, maxVal, maxVal));
    };
    Vector3.prototype.clampLength = function (min, max) {
        return this.divideScalar(this.length() || 1).multiplyScalar(Math.max(min, Math.min(max, length)));
    };
    /**
     *
     * @param m
     */
    Vector3.prototype.applyMatrix4 = function (m) {
        var x = this.x, y = this.y, z = this.z;
        var e = m.elements;
        var w = 1 / (e[3] * x + e[7] * y + e[11] * z + e[15]);
        this.x = (e[0] * x + e[4] * y + e[8] * z + e[12]) * w;
        this.y = (e[1] * x + e[5] * y + e[9] * z + e[13]) * w;
        this.z = (e[2] * x + e[6] * y + e[10] * z + e[14]) * w;
        return this;
    };
    /**
     * 从矩阵获得位置
     * @param m
     */
    Vector3.prototype.setFromMatrixPosition = function (m) {
        var e = m.elements;
        this.x = e[12];
        this.y = e[13];
        this.z = e[14];
        return this;
    };
    /**
     * 从矩阵获得缩放值
     * @param m
     */
    Vector3.prototype.setFromMatrixScale = function (m) {
        var sx = this.setFromMatrixColumn(m, 0).length();
        var sy = this.setFromMatrixColumn(m, 1).length();
        var sz = this.setFromMatrixColumn(m, 2).length();
        this.x = sx;
        this.y = sy;
        this.z = sz;
        return this;
    };
    Vector3.prototype.setFromMatrixColumn = function (m, index) {
        return this.fromArray(m.elements, index * 4);
    };
    Vector3.prototype.transformDirection = function (m) {
        var x = this.x, y = this.y, z = this.z;
        var e = m.elements;
        this.x = e[0] * x + e[4] * y + e[8] * z;
        this.y = e[1] * x + e[5] * y + e[9] * z;
        this.z = e[2] * x + e[6] * y + e[10] * z;
        return this.normalize();
    };
    /**
     * 转换成屏幕坐标，范围-1到1，可根据stage转换成stage上坐标，或者canvas坐标
     * @param camera
     */
    Vector3.prototype.project = function (camera) {
        return this.applyMatrix4(camera.worldMatrixInverse).applyMatrix4(camera.projectionMatrix);
    };
    Vector3.prototype.unproject = function (camera) {
        return this.applyMatrix4(new Matrix4().setInverseOf(camera.projectionMatrix)).applyMatrix4(camera._worldMatrix);
    };
    Vector3.prototype.equals = function (v) {
        return ((v.x === this.x) && (v.y === this.y) && (v.z === this.z));
    };
    Vector3.prototype.fromArray = function (array, offset) {
        if (offset === void 0) { offset = 0; }
        this.x = array[offset];
        this.y = array[offset + 1];
        this.z = array[offset + 2];
        return this;
    };
    Vector3.prototype.toArray = function (array, offset) {
        if (array === void 0) { array = []; }
        if (offset === void 0) { offset = 0; }
        array[offset] = this.x;
        array[offset + 1] = this.y;
        array[offset + 2] = this.z;
        return array;
    };
    return Vector3;
}());

var Matrix4 = /** @class */ (function () {
    function Matrix4() {
        this.elements = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
    }
    /**
     * 初始化本矩阵
     */
    Matrix4.prototype.setIdentity = function () {
        var e = this.elements;
        e[0] = 1;
        e[4] = 0;
        e[8] = 0;
        e[12] = 0;
        e[1] = 0;
        e[5] = 1;
        e[9] = 0;
        e[13] = 0;
        e[2] = 0;
        e[6] = 0;
        e[10] = 1;
        e[14] = 0;
        e[3] = 0;
        e[7] = 0;
        e[11] = 0;
        e[15] = 1;
        return this;
    };
    Matrix4.prototype.set = function (n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44) {
        var te = this.elements;
        te[0] = n11;
        te[4] = n12;
        te[8] = n13;
        te[12] = n14;
        te[1] = n21;
        te[5] = n22;
        te[9] = n23;
        te[13] = n24;
        te[2] = n31;
        te[6] = n32;
        te[10] = n33;
        te[14] = n34;
        te[3] = n41;
        te[7] = n42;
        te[11] = n43;
        te[15] = n44;
        return this;
    };
    Matrix4.prototype.copy = function (src) {
        var i, s, d;
        s = src.elements;
        d = this.elements;
        for (i = 0; i < 16; ++i)
            d[i] = s[i];
        return this;
    };
    Matrix4.prototype.clone = function () {
        return new Matrix4().fromArray(this.elements);
    };
    Matrix4.prototype.equals = function (matrix) {
        var te = this.elements;
        var me = matrix.elements;
        for (var i = 0; i < 16; i++) {
            if (te[i] !== me[i])
                return false;
        }
        return true;
    };
    Matrix4.prototype.fromArray = function (array, offset) {
        if (offset === void 0) { offset = 0; }
        for (var i = 0; i < 16; i++)
            this.elements[i] = array[i + offset];
        return this;
    };
    Matrix4.prototype.toArray = function (array, offset) {
        if (array === void 0) { array = []; }
        if (offset === void 0) { offset = 0; }
        var te = this.elements;
        array[offset] = te[0];
        array[offset + 1] = te[1];
        array[offset + 2] = te[2];
        array[offset + 3] = te[3];
        array[offset + 4] = te[4];
        array[offset + 5] = te[5];
        array[offset + 6] = te[6];
        array[offset + 7] = te[7];
        array[offset + 8] = te[8];
        array[offset + 9] = te[9];
        array[offset + 10] = te[10];
        array[offset + 11] = te[11];
        array[offset + 12] = te[12];
        array[offset + 13] = te[13];
        array[offset + 14] = te[14];
        array[offset + 15] = te[15];
        return array;
    };
    /**
     * Multiply the matrix from the right.
     * @param other The multiply matrix
     * @return this
     */
    Matrix4.prototype.concat = function (other) {
        var i, e, a, b, ai0, ai1, ai2, ai3;
        // Calculate e = a * b
        e = this.elements;
        a = this.elements;
        b = other.elements;
        // If e equals b, copy b to temporary matrix.
        if (e === b) {
            b = new Float32Array(16);
            for (i = 0; i < 16; ++i) {
                b[i] = e[i];
            }
        }
        for (i = 0; i < 4; i++) {
            ai0 = a[i];
            ai1 = a[i + 4];
            ai2 = a[i + 8];
            ai3 = a[i + 12];
            e[i] = ai0 * b[0] + ai1 * b[1] + ai2 * b[2] + ai3 * b[3];
            e[i + 4] = ai0 * b[4] + ai1 * b[5] + ai2 * b[6] + ai3 * b[7];
            e[i + 8] = ai0 * b[8] + ai1 * b[9] + ai2 * b[10] + ai3 * b[11];
            e[i + 12] = ai0 * b[12] + ai1 * b[13] + ai2 * b[14] + ai3 * b[15];
        }
        return this;
    };
    // multiply = this.concat;
    Matrix4.prototype.multiply = function (m) {
        return this.multiplyMatrices(this, m);
    };
    Matrix4.prototype.premultiply = function (m) {
        return this.multiplyMatrices(m, this);
    };
    Matrix4.prototype.multiplyMatrices = function (a, b) {
        var ae = a.elements;
        var be = b.elements;
        var te = this.elements;
        var a11 = ae[0], a12 = ae[4], a13 = ae[8], a14 = ae[12];
        var a21 = ae[1], a22 = ae[5], a23 = ae[9], a24 = ae[13];
        var a31 = ae[2], a32 = ae[6], a33 = ae[10], a34 = ae[14];
        var a41 = ae[3], a42 = ae[7], a43 = ae[11], a44 = ae[15];
        var b11 = be[0], b12 = be[4], b13 = be[8], b14 = be[12];
        var b21 = be[1], b22 = be[5], b23 = be[9], b24 = be[13];
        var b31 = be[2], b32 = be[6], b33 = be[10], b34 = be[14];
        var b41 = be[3], b42 = be[7], b43 = be[11], b44 = be[15];
        te[0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
        te[4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
        te[8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
        te[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
        te[1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
        te[5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
        te[9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
        te[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
        te[2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
        te[6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
        te[10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
        te[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
        te[3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
        te[7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
        te[11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
        te[15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
        return this;
    };
    /**
     * Multiply the three-dimensional vector.
     * @param pos  The multiply vector
     * @return The result of multiplication(Float32Array)
     */
    Matrix4.prototype.multiplyVector3 = function (pos) {
        var e = this.elements;
        return new Vector3().set(pos.x * e[0] + pos.y * e[4] + pos.z * e[8] + e[12], pos.x * e[1] + pos.y * e[5] + pos.z * e[9] + e[13], pos.x * e[2] + pos.y * e[6] + pos.z * e[10] + e[14]);
    };
    /**
     * Multiply the four-dimensional vector.
     * @param pos  The multiply vector
     * @return The result of multiplication(Float32Array)
     */
    // multiplyVector4(pos) {
    //     var e = this.elements;
    //     var p = pos.elements;
    //     var v = new Vector4();
    //     var result = v.elements;
    //     result[0] = p[0] * e[0] + p[1] * e[4] + p[2] * e[8] + p[3] * e[12];
    //     result[1] = p[0] * e[1] + p[1] * e[5] + p[2] * e[9] + p[3] * e[13];
    //     result[2] = p[0] * e[2] + p[1] * e[6] + p[2] * e[10] + p[3] * e[14];
    //     result[3] = p[0] * e[3] + p[1] * e[7] + p[2] * e[11] + p[3] * e[15];
    //     return v;
    // };
    /**
     * Transpose the matrix.转置
     * @return this
     */
    Matrix4.prototype.transpose = function () {
        var e, t;
        e = this.elements;
        t = e[1];
        e[1] = e[4];
        e[4] = t;
        t = e[2];
        e[2] = e[8];
        e[8] = t;
        t = e[3];
        e[3] = e[12];
        e[12] = t;
        t = e[6];
        e[6] = e[9];
        e[9] = t;
        t = e[7];
        e[7] = e[13];
        e[13] = t;
        t = e[11];
        e[11] = e[14];
        e[14] = t;
        return this;
    };
    /**
     * Calculate the inverse matrix of specified matrix, and set to this.将一矩阵的逆赋给自己
     * @param other The source matrix
     * @return this
     */
    Matrix4.prototype.setInverseOf = function (other) {
        var i, s, d, inv, det;
        s = other.elements;
        d = this.elements;
        inv = new Float32Array(16);
        inv[0] = s[5] * s[10] * s[15] - s[5] * s[11] * s[14] - s[9] * s[6] * s[15]
            + s[9] * s[7] * s[14] + s[13] * s[6] * s[11] - s[13] * s[7] * s[10];
        inv[4] = -s[4] * s[10] * s[15] + s[4] * s[11] * s[14] + s[8] * s[6] * s[15]
            - s[8] * s[7] * s[14] - s[12] * s[6] * s[11] + s[12] * s[7] * s[10];
        inv[8] = s[4] * s[9] * s[15] - s[4] * s[11] * s[13] - s[8] * s[5] * s[15]
            + s[8] * s[7] * s[13] + s[12] * s[5] * s[11] - s[12] * s[7] * s[9];
        inv[12] = -s[4] * s[9] * s[14] + s[4] * s[10] * s[13] + s[8] * s[5] * s[14]
            - s[8] * s[6] * s[13] - s[12] * s[5] * s[10] + s[12] * s[6] * s[9];
        inv[1] = -s[1] * s[10] * s[15] + s[1] * s[11] * s[14] + s[9] * s[2] * s[15]
            - s[9] * s[3] * s[14] - s[13] * s[2] * s[11] + s[13] * s[3] * s[10];
        inv[5] = s[0] * s[10] * s[15] - s[0] * s[11] * s[14] - s[8] * s[2] * s[15]
            + s[8] * s[3] * s[14] + s[12] * s[2] * s[11] - s[12] * s[3] * s[10];
        inv[9] = -s[0] * s[9] * s[15] + s[0] * s[11] * s[13] + s[8] * s[1] * s[15]
            - s[8] * s[3] * s[13] - s[12] * s[1] * s[11] + s[12] * s[3] * s[9];
        inv[13] = s[0] * s[9] * s[14] - s[0] * s[10] * s[13] - s[8] * s[1] * s[14]
            + s[8] * s[2] * s[13] + s[12] * s[1] * s[10] - s[12] * s[2] * s[9];
        inv[2] = s[1] * s[6] * s[15] - s[1] * s[7] * s[14] - s[5] * s[2] * s[15]
            + s[5] * s[3] * s[14] + s[13] * s[2] * s[7] - s[13] * s[3] * s[6];
        inv[6] = -s[0] * s[6] * s[15] + s[0] * s[7] * s[14] + s[4] * s[2] * s[15]
            - s[4] * s[3] * s[14] - s[12] * s[2] * s[7] + s[12] * s[3] * s[6];
        inv[10] = s[0] * s[5] * s[15] - s[0] * s[7] * s[13] - s[4] * s[1] * s[15]
            + s[4] * s[3] * s[13] + s[12] * s[1] * s[7] - s[12] * s[3] * s[5];
        inv[14] = -s[0] * s[5] * s[14] + s[0] * s[6] * s[13] + s[4] * s[1] * s[14]
            - s[4] * s[2] * s[13] - s[12] * s[1] * s[6] + s[12] * s[2] * s[5];
        inv[3] = -s[1] * s[6] * s[11] + s[1] * s[7] * s[10] + s[5] * s[2] * s[11]
            - s[5] * s[3] * s[10] - s[9] * s[2] * s[7] + s[9] * s[3] * s[6];
        inv[7] = s[0] * s[6] * s[11] - s[0] * s[7] * s[10] - s[4] * s[2] * s[11]
            + s[4] * s[3] * s[10] + s[8] * s[2] * s[7] - s[8] * s[3] * s[6];
        inv[11] = -s[0] * s[5] * s[11] + s[0] * s[7] * s[9] + s[4] * s[1] * s[11]
            - s[4] * s[3] * s[9] - s[8] * s[1] * s[7] + s[8] * s[3] * s[5];
        inv[15] = s[0] * s[5] * s[10] - s[0] * s[6] * s[9] - s[4] * s[1] * s[10]
            + s[4] * s[2] * s[9] + s[8] * s[1] * s[6] - s[8] * s[2] * s[5];
        det = s[0] * inv[0] + s[1] * inv[4] + s[2] * inv[8] + s[3] * inv[12];
        if (det === 0)
            return this;
        det = 1 / det;
        for (i = 0; i < 16; i++)
            d[i] = inv[i] * det;
        return this;
    };
    /**
     * Calculate the inverse matrix of this, and set to this.
     * @return this
     */
    Matrix4.prototype.invert = function () {
        return this.setInverseOf(this);
    };
    /**
     * 设置为正交投影矩阵
     * @param left The coordinate of the left of clipping plane.
     * @param right The coordinate of the right of clipping plane.
     * @param top The coordinate of the top top clipping plane.
     * @param bottom The coordinate of the bottom of clipping plane.
     * @param near The distances to the nearer depth clipping plane. This value is minus if the plane is to be behind the viewer.
     * @param far The distances to the farther depth clipping plane. This value is minus if the plane is to be behind the viewer.
     * @return this
     */
    Matrix4.prototype.setOrtho = function (left, right, top, bottom, near, far) {
        var e, rw, rh, rd;
        if (left === right || bottom === top || near === far) {
            throw 'null frustum';
        }
        rw = 1 / (right - left);
        rh = 1 / (top - bottom);
        rd = 1 / (far - near);
        e = this.elements;
        e[0] = 2 * rw;
        e[1] = 0;
        e[2] = 0;
        e[3] = 0;
        e[4] = 0;
        e[5] = 2 * rh;
        e[6] = 0;
        e[7] = 0;
        e[8] = 0;
        e[9] = 0;
        e[10] = -2 * rd;
        e[11] = 0;
        e[12] = -(right + left) * rw;
        e[13] = -(top + bottom) * rh;
        e[14] = -(far + near) * rd;
        e[15] = 1;
        return this;
    };
    /**
     * Multiply the orthographic projection matrix from the right.
     * @param left The coordinate of the left of clipping plane.
     * @param right The coordinate of the right of clipping plane.
     * @param top The coordinate of the top top clipping plane.
     * @param bottom The coordinate of the bottom of clipping plane.
     * @param near The distances to the nearer depth clipping plane. This value is minus if the plane is to be behind the viewer.
     * @param far The distances to the farther depth clipping plane. This value is minus if the plane is to be behind the viewer.
     * @return this
     */
    Matrix4.prototype.ortho = function (left, right, top, bottom, near, far) {
        return this.concat(new Matrix4().setOrtho(left, right, top, bottom, near, far));
    };
    /**
     * Set the perspective projection matrix.
     * @param left The coordinate of the left of clipping plane.
     * @param right The coordinate of the right of clipping plane.
     * @param bottom The coordinate of the bottom of clipping plane.
     * @param top The coordinate of the top top clipping plane.
     * @param near The distances to the nearer depth clipping plane. This value must be plus value.
     * @param far The distances to the farther depth clipping plane. This value must be plus value.
     * @return this
     */
    Matrix4.prototype.setFrustum = function (left, right, bottom, top, near, far) {
        var e, rw, rh, rd;
        if (left === right || top === bottom || near === far) {
            throw 'null frustum';
        }
        if (near <= 0) {
            throw 'near <= 0';
        }
        if (far <= 0) {
            throw 'far <= 0';
        }
        rw = 1 / (right - left);
        rh = 1 / (top - bottom);
        rd = 1 / (far - near);
        e = this.elements;
        e[0] = 2 * near * rw;
        e[1] = 0;
        e[2] = 0;
        e[3] = 0;
        e[4] = 0;
        e[5] = 2 * near * rh;
        e[6] = 0;
        e[7] = 0;
        e[8] = (right + left) * rw;
        e[9] = (top + bottom) * rh;
        e[10] = -(far + near) * rd;
        e[11] = -1;
        e[12] = 0;
        e[13] = 0;
        e[14] = -2 * near * far * rd;
        e[15] = 0;
        return this;
    };
    /**
     * Multiply the perspective projection matrix from the right.
     * @param left The coordinate of the left of clipping plane.
     * @param right The coordinate of the right of clipping plane.
     * @param bottom The coordinate of the bottom of clipping plane.
     * @param top The coordinate of the top top clipping plane.
     * @param near The distances to the nearer depth clipping plane. This value must be plus value.
     * @param far The distances to the farther depth clipping plane. This value must be plus value.
     * @return this
     */
    Matrix4.prototype.frustum = function (left, right, bottom, top, near, far) {
        return this.concat(new Matrix4().setFrustum(left, right, bottom, top, near, far));
    };
    /**
     * Set the perspective projection matrix by fovy and aspect.
     * @param fovy The angle between the upper and lower sides of the frustum.
     * @param aspect The aspect ratio of the frustum. (width/height)
     * @param near The distances to the nearer depth clipping plane. This value must be plus value.
     * @param far The distances to the farther depth clipping plane. This value must be plus value.
     * @return this
     */
    Matrix4.prototype.setPerspective = function (fovy, aspect, near, far) {
        var e, rd, s, ct;
        if (near === far || aspect === 0) {
            throw 'null frustum';
        }
        if (near <= 0) {
            throw 'near <= 0';
        }
        if (far <= 0) {
            throw 'far <= 0';
        }
        fovy = Math.PI * fovy / 180 / 2;
        s = Math.sin(fovy);
        if (s === 0) {
            throw 'null frustum';
        }
        rd = 1 / (far - near);
        ct = Math.cos(fovy) / s;
        e = this.elements;
        e[0] = ct / aspect;
        e[1] = 0;
        e[2] = 0;
        e[3] = 0;
        e[4] = 0;
        e[5] = ct;
        e[6] = 0;
        e[7] = 0;
        e[8] = 0;
        e[9] = 0;
        e[10] = -(far + near) * rd;
        e[11] = -1;
        e[12] = 0;
        e[13] = 0;
        e[14] = -2 * near * far * rd;
        e[15] = 0;
        return this;
    };
    Matrix4.prototype.makePerspective = function (left, right, top, bottom, near, far) {
        // var near = this.near,
        //     top = near * Math.tan(_Math.DEG2RAD * 0.5 * this.fov) / this.zoom,
        //     height = 2 * top,
        //     width = this.aspect * height,
        //     left = - 0.5 * width,
        var te = this.elements;
        var x = 2 * near / (right - left);
        var y = 2 * near / (top - bottom);
        var a = (right + left) / (right - left);
        var b = (top + bottom) / (top - bottom);
        var c = -(far + near) / (far - near);
        var d = -2 * far * near / (far - near);
        te[0] = x;
        te[4] = 0;
        te[8] = a;
        te[12] = 0;
        te[1] = 0;
        te[5] = y;
        te[9] = b;
        te[13] = 0;
        te[2] = 0;
        te[6] = 0;
        te[10] = c;
        te[14] = d;
        te[3] = 0;
        te[7] = 0;
        te[11] = -1;
        te[15] = 0;
        return this;
    };
    /**
     * Multiply the perspective projection matrix from the right.
     * @param fovy The angle between the upper and lower sides of the frustum.
     * @param aspect The aspect ratio of the frustum. (width/height)
     * @param near The distances to the nearer depth clipping plane. This value must be plus value.
     * @param far The distances to the farther depth clipping plane. This value must be plus value.
     * @return this
     */
    Matrix4.prototype.perspective = function (fovy, aspect, near, far) {
        return this.concat(new Matrix4().setPerspective(fovy, aspect, near, far));
    };
    /**
     * Set the matrix for scaling.
     * @param x The scale factor along the X axis
     * @param y The scale factor along the Y axis
     * @param z The scale factor along the Z axis
     * @return this
     */
    Matrix4.prototype.setScale = function (x, y, z) {
        var e = this.elements;
        e[0] = x;
        e[4] = 0;
        e[8] = 0;
        e[12] = 0;
        e[1] = 0;
        e[5] = y;
        e[9] = 0;
        e[13] = 0;
        e[2] = 0;
        e[6] = 0;
        e[10] = z;
        e[14] = 0;
        e[3] = 0;
        e[7] = 0;
        e[11] = 0;
        e[15] = 1;
        return this;
    };
    /**
     * Multiply the matrix for scaling from the right.
     * @param x The scale factor along the X axis
     * @param y The scale factor along the Y axis
     * @param z The scale factor along the Z axis
     * @return this
     */
    Matrix4.prototype.scale = function (x, y, z) {
        var e = this.elements;
        e[0] *= x;
        e[4] *= y;
        e[8] *= z;
        e[1] *= x;
        e[5] *= y;
        e[9] *= z;
        e[2] *= x;
        e[6] *= y;
        e[10] *= z;
        e[3] *= x;
        e[7] *= y;
        e[11] *= z;
        return this;
    };
    Matrix4.prototype.getMaxScaleOnAxis = function () {
        var te = this.elements;
        var scaleXSq = te[0] * te[0] + te[1] * te[1] + te[2] * te[2];
        var scaleYSq = te[4] * te[4] + te[5] * te[5] + te[6] * te[6];
        var scaleZSq = te[8] * te[8] + te[9] * te[9] + te[10] * te[10];
        return Math.sqrt(Math.max(scaleXSq, scaleYSq, scaleZSq));
    };
    /**
     * Set the matrix for translation.
     * @param x The X value of a translation.
     * @param y The Y value of a translation.
     * @param z The Z value of a translation.
     * @return this
     */
    Matrix4.prototype.setTranslate = function (x, y, z) {
        var e = this.elements;
        e[0] = 1;
        e[4] = 0;
        e[8] = 0;
        e[12] = x;
        e[1] = 0;
        e[5] = 1;
        e[9] = 0;
        e[13] = y;
        e[2] = 0;
        e[6] = 0;
        e[10] = 1;
        e[14] = z;
        e[3] = 0;
        e[7] = 0;
        e[11] = 0;
        e[15] = 1;
        return this;
    };
    /**
     * Multiply the matrix for translation from the right.
     * @param x The X value of a translation.
     * @param y The Y value of a translation.
     * @param z The Z value of a translation.
     * @return this
     */
    Matrix4.prototype.translate = function (x, y, z) {
        var e = this.elements;
        e[12] += e[0] * x + e[4] * y + e[8] * z;
        e[13] += e[1] * x + e[5] * y + e[9] * z;
        e[14] += e[2] * x + e[6] * y + e[10] * z;
        e[15] += e[3] * x + e[7] * y + e[11] * z;
        return this;
    };
    /**
     * Set the matrix for rotation.
     * The vector of rotation axis may not be normalized.
     * @param angle The angle of rotation (degrees)
     * @param x The X coordinate of vector of rotation axis.
     * @param y The Y coordinate of vector of rotation axis.
     * @param z The Z coordinate of vector of rotation axis.
     * @return this
     */
    Matrix4.prototype.setRotate = function (angle, x, y, z) {
        var e, s, c, len, rlen, nc, xy, yz, zx, xs, ys, zs;
        angle = Math.PI * angle / 180;
        e = this.elements;
        s = Math.sin(angle);
        c = Math.cos(angle);
        if (0 !== x && 0 === y && 0 === z) {
            // Rotation around X axis
            if (x < 0) {
                s = -s;
            }
            e[0] = 1;
            e[4] = 0;
            e[8] = 0;
            e[12] = 0;
            e[1] = 0;
            e[5] = c;
            e[9] = -s;
            e[13] = 0;
            e[2] = 0;
            e[6] = s;
            e[10] = c;
            e[14] = 0;
            e[3] = 0;
            e[7] = 0;
            e[11] = 0;
            e[15] = 1;
        }
        else if (0 === x && 0 !== y && 0 === z) {
            // Rotation around Y axis
            if (y < 0) {
                s = -s;
            }
            e[0] = c;
            e[4] = 0;
            e[8] = s;
            e[12] = 0;
            e[1] = 0;
            e[5] = 1;
            e[9] = 0;
            e[13] = 0;
            e[2] = -s;
            e[6] = 0;
            e[10] = c;
            e[14] = 0;
            e[3] = 0;
            e[7] = 0;
            e[11] = 0;
            e[15] = 1;
        }
        else if (0 === x && 0 === y && 0 !== z) {
            // Rotation around Z axis
            if (z < 0) {
                s = -s;
            }
            e[0] = c;
            e[4] = -s;
            e[8] = 0;
            e[12] = 0;
            e[1] = s;
            e[5] = c;
            e[9] = 0;
            e[13] = 0;
            e[2] = 0;
            e[6] = 0;
            e[10] = 1;
            e[14] = 0;
            e[3] = 0;
            e[7] = 0;
            e[11] = 0;
            e[15] = 1;
        }
        else {
            // Rotation around another axis
            len = Math.sqrt(x * x + y * y + z * z);
            if (len !== 1) {
                rlen = 1 / len;
                x *= rlen;
                y *= rlen;
                z *= rlen;
            }
            nc = 1 - c;
            xy = x * y;
            yz = y * z;
            zx = z * x;
            xs = x * s;
            ys = y * s;
            zs = z * s;
            e[0] = x * x * nc + c;
            e[1] = xy * nc + zs;
            e[2] = zx * nc - ys;
            e[3] = 0;
            e[4] = xy * nc - zs;
            e[5] = y * y * nc + c;
            e[6] = yz * nc + xs;
            e[7] = 0;
            e[8] = zx * nc + ys;
            e[9] = yz * nc - xs;
            e[10] = z * z * nc + c;
            e[11] = 0;
            e[12] = 0;
            e[13] = 0;
            e[14] = 0;
            e[15] = 1;
        }
        return this;
    };
    Matrix4.prototype.makeRotationAxis = function (axis, angle) {
        // Based on http://www.gamedev.net/reference/articles/article1199.asp
        var c = Math.cos(angle);
        var s = Math.sin(angle);
        var t = 1 - c;
        var x = axis.x, y = axis.y, z = axis.z;
        var tx = t * x, ty = t * y;
        this.set(tx * x + c, tx * y - s * z, tx * z + s * y, 0, tx * y + s * z, ty * y + c, ty * z - s * x, 0, tx * z - s * y, ty * z + s * x, t * z * z + c, 0, 0, 0, 0, 1);
        return this;
    };
    /**
     * Multiply the matrix for rotation from the right.
     * The vector of rotation axis may not be normalized.
     * @param angle The angle of rotation (degrees)
     * @param x The X coordinate of vector of rotation axis.
     * @param y The Y coordinate of vector of rotation axis.
     * @param z The Z coordinate of vector of rotation axis.
     * @return this
     */
    Matrix4.prototype.rotate = function (angle, x, y, z) {
        return this.concat(new Matrix4().setRotate(angle, x, y, z));
    };
    /**
     * Set the viewing matrix.
     * @param eyeX, eyeY, eyeZ The position of the eye point.
     * @param centerX, centerY, centerZ The position of the reference point.
     * @param upX, upY, upZ The direction of the up vector.
     * @return this
     */
    Matrix4.prototype.setLookAt = function (eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ) {
        var e, fx, fy, fz, rlf, sx, sy, sz, rls, ux, uy, uz;
        fx = centerX - eyeX;
        fy = centerY - eyeY;
        fz = centerZ - eyeZ;
        // Normalize f.
        rlf = 1 / Math.sqrt(fx * fx + fy * fy + fz * fz);
        fx *= rlf;
        fy *= rlf;
        fz *= rlf;
        // Calculate cross product of f and up.
        sx = fy * upZ - fz * upY;
        sy = fz * upX - fx * upZ;
        sz = fx * upY - fy * upX;
        // Normalize s.
        rls = 1 / Math.sqrt(sx * sx + sy * sy + sz * sz);
        sx *= rls;
        sy *= rls;
        sz *= rls;
        // Calculate cross product of s and f.
        ux = sy * fz - sz * fy;
        uy = sz * fx - sx * fz;
        uz = sx * fy - sy * fx;
        // Set to this.
        e = this.elements;
        e[0] = sx;
        e[1] = ux;
        e[2] = -fx;
        e[3] = 0;
        e[4] = sy;
        e[5] = uy;
        e[6] = -fy;
        e[7] = 0;
        e[8] = sz;
        e[9] = uz;
        e[10] = -fz;
        e[11] = 0;
        e[12] = 0;
        e[13] = 0;
        e[14] = 0;
        e[15] = 1;
        // Translate.
        return this.translate(-eyeX, -eyeY, -eyeZ);
    };
    // lookAt(eye: Vector3, center: Vector3, up: Vector3) {
    //     // return this.concat(new Matrix4().setLookAt(
    //     //     eye.x, eye.y, eye.z,
    //     //     center.x, center.y, center.z,
    //     //     up.x, up.y, up.z));
    //     return this.setLookAt(
    //         eye.x, eye.y, eye.z,
    //         center.x, center.y, center.z,
    //         up.x, up.y, up.z);
    // };
    //three上的，上面的setLookAt后的矩阵就是视图矩阵
    Matrix4.prototype.lookAt = function (eye, target, up) {
        var x = new Vector3();
        var y = new Vector3();
        var z = new Vector3();
        var te = this.elements;
        z.subVectors(eye, target);
        if (z.lengthSq() === 0) {
            // eye and target are in the same position
            z.z = 1;
        }
        z.normalize();
        x.crossVectors(up, z);
        if (x.lengthSq() === 0) {
            // up and z are parallel
            if (Math.abs(up.z) === 1) {
                z.x += 0.0001;
            }
            else {
                z.z += 0.0001;
            }
            z.normalize();
            x.crossVectors(up, z);
        }
        x.normalize();
        y.crossVectors(z, x);
        te[0] = x.x;
        te[4] = y.x;
        te[8] = z.x;
        te[1] = x.y;
        te[5] = y.y;
        te[9] = z.y;
        te[2] = x.z;
        te[6] = y.z;
        te[10] = z.z;
        return this;
    };
    /**
     * Multiply the matrix for project vertex to plane from the right.
     * @param plane The array[A, B, C, D] of the equation of plane "Ax + By + Cz + D = 0".
     * @param light The array which stored coordinates of the light. if light[3]=0, treated as parallel light.
     * @return this
     */
    Matrix4.prototype.dropShadow = function (plane, light) {
        var mat = new Matrix4();
        var e = mat.elements;
        var dot = plane[0] * light[0] + plane[1] * light[1] + plane[2] * light[2] + plane[3] * light[3];
        e[0] = dot - light[0] * plane[0];
        e[1] = -light[1] * plane[0];
        e[2] = -light[2] * plane[0];
        e[3] = -light[3] * plane[0];
        e[4] = -light[0] * plane[1];
        e[5] = dot - light[1] * plane[1];
        e[6] = -light[2] * plane[1];
        e[7] = -light[3] * plane[1];
        e[8] = -light[0] * plane[2];
        e[9] = -light[1] * plane[2];
        e[10] = dot - light[2] * plane[2];
        e[11] = -light[3] * plane[2];
        e[12] = -light[0] * plane[3];
        e[13] = -light[1] * plane[3];
        e[14] = -light[2] * plane[3];
        e[15] = dot - light[3] * plane[3];
        return this.concat(mat);
    };
    /**
     * Multiply the matrix for project vertex to plane from the right.(Projected by parallel light.)
     * @param normX, normY, normZ The normal vector of the plane.(Not necessary to be normalized.)
     * @param planeX, planeY, planeZ The coordinate of arbitrary points on a plane.
     * @param lightX, lightY, lightZ The vector of the direction of light.(Not necessary to be normalized.)
     * @return this
     */
    Matrix4.prototype.dropShadowDirectionally = function (normX, normY, normZ, planeX, planeY, planeZ, lightX, lightY, lightZ) {
        var a = planeX * normX + planeY * normY + planeZ * normZ;
        return this.dropShadow([normX, normY, normZ, -a], [lightX, lightY, lightZ, 0]);
    };
    Matrix4.prototype.makeRotationFromQuaternion = function (q) {
        var zero = new Vector3(0, 0, 0);
        var one = new Vector3(1, 1, 1);
        return this.compose(zero, q, one);
    };
    Matrix4.prototype.compose = function (position, quaternion, scale) {
        var te = this.elements;
        var x = quaternion.x, y = quaternion.y, z = quaternion.z, w = quaternion.w;
        var x2 = x + x, y2 = y + y, z2 = z + z;
        var xx = x * x2, xy = x * y2, xz = x * z2;
        var yy = y * y2, yz = y * z2, zz = z * z2;
        var wx = w * x2, wy = w * y2, wz = w * z2;
        var sx = scale.x, sy = scale.y, sz = scale.z;
        te[0] = (1 - (yy + zz)) * sx;
        te[1] = (xy + wz) * sx;
        te[2] = (xz - wy) * sx;
        te[3] = 0;
        te[4] = (xy - wz) * sy;
        te[5] = (1 - (xx + zz)) * sy;
        te[6] = (yz + wx) * sy;
        te[7] = 0;
        te[8] = (xz + wy) * sz;
        te[9] = (yz - wx) * sz;
        te[10] = (1 - (xx + yy)) * sz;
        te[11] = 0;
        te[12] = position.x;
        te[13] = position.y;
        te[14] = position.z;
        te[15] = 1;
        return this;
    };
    Matrix4.prototype.decompose = function (position, quaternion, scale) {
        var vector = new Vector3();
        var matrix = new Matrix4();
        var te = this.elements;
        var sx = vector.set(te[0], te[1], te[2]).length();
        var sy = vector.set(te[4], te[5], te[6]).length();
        var sz = vector.set(te[8], te[9], te[10]).length();
        // if determine is negative, we need to invert one scale
        var det = this.determinant();
        if (det < 0)
            sx = -sx;
        position.x = te[12];
        position.y = te[13];
        position.z = te[14];
        // scale the rotation part
        matrix.copy(this);
        var invSX = 1 / sx;
        var invSY = 1 / sy;
        var invSZ = 1 / sz;
        matrix.elements[0] *= invSX;
        matrix.elements[1] *= invSX;
        matrix.elements[2] *= invSX;
        matrix.elements[4] *= invSY;
        matrix.elements[5] *= invSY;
        matrix.elements[6] *= invSY;
        matrix.elements[8] *= invSZ;
        matrix.elements[9] *= invSZ;
        matrix.elements[10] *= invSZ;
        quaternion.setFromRotationMatrix(matrix);
        scale.x = sx;
        scale.y = sy;
        scale.z = sz;
        return this;
    };
    Matrix4.prototype.determinant = function () {
        var te = this.elements;
        var n11 = te[0], n12 = te[4], n13 = te[8], n14 = te[12];
        var n21 = te[1], n22 = te[5], n23 = te[9], n24 = te[13];
        var n31 = te[2], n32 = te[6], n33 = te[10], n34 = te[14];
        var n41 = te[3], n42 = te[7], n43 = te[11], n44 = te[15];
        //TODO: make this more efficient
        //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )
        return (n41 * (+n14 * n23 * n32
            - n13 * n24 * n32
            - n14 * n22 * n33
            + n12 * n24 * n33
            + n13 * n22 * n34
            - n12 * n23 * n34) +
            n42 * (+n11 * n23 * n34
                - n11 * n24 * n33
                + n14 * n21 * n33
                - n13 * n21 * n34
                + n13 * n24 * n31
                - n14 * n23 * n31) +
            n43 * (+n11 * n24 * n32
                - n11 * n22 * n34
                - n14 * n21 * n32
                + n12 * n21 * n34
                + n14 * n22 * n31
                - n12 * n24 * n31) +
            n44 * (-n13 * n22 * n31
                - n11 * n23 * n32
                + n11 * n22 * n33
                + n13 * n21 * n32
                - n12 * n21 * n33
                + n12 * n23 * n31));
    };
    Matrix4.prototype.extractRotation = function (m) {
        var v1 = new Vector3();
        var te = this.elements;
        var me = m.elements;
        var scaleX = 1 / v1.setFromMatrixColumn(m, 0).length();
        var scaleY = 1 / v1.setFromMatrixColumn(m, 1).length();
        var scaleZ = 1 / v1.setFromMatrixColumn(m, 2).length();
        te[0] = me[0] * scaleX;
        te[1] = me[1] * scaleX;
        te[2] = me[2] * scaleX;
        te[3] = 0;
        te[4] = me[4] * scaleY;
        te[5] = me[5] * scaleY;
        te[6] = me[6] * scaleY;
        te[7] = 0;
        te[8] = me[8] * scaleZ;
        te[9] = me[9] * scaleZ;
        te[10] = me[10] * scaleZ;
        te[11] = 0;
        te[12] = 0;
        te[13] = 0;
        te[14] = 0;
        te[15] = 1;
        return this;
    };
    return Matrix4;
}());

var Quaternion = /** @class */ (function () {
    function Quaternion(x, y, z, w) {
        this.setFromUnitVectors = function () {
            // assumes direction vectors vFrom and vTo are normalized
            var v1 = new Vector3();
            var r;
            var EPS = 0.000001;
            return function setFromUnitVectors(vFrom, vTo) {
                if (v1 === undefined)
                    v1 = new Vector3();
                r = vFrom.dot(vTo) + 1;
                if (r < EPS) {
                    r = 0;
                    if (Math.abs(vFrom.x) > Math.abs(vFrom.z)) {
                        v1.set(-vFrom.y, vFrom.x, 0);
                    }
                    else {
                        v1.set(0, -vFrom.z, vFrom.y);
                    }
                }
                else {
                    v1.crossVectors(vFrom, vTo);
                }
                this._x = v1.x;
                this._y = v1.y;
                this._z = v1.z;
                this._w = r;
                return this.normalize();
            };
        }();
        this._x = x || 0;
        this._y = y || 0;
        this._z = z || 0;
        this._w = (w !== undefined) ? w : 1;
    }
    Quaternion.slerp = function (qa, qb, qm, t) {
        return qm.copy(qa).slerp(qb, t);
    };
    Quaternion.slerpFlat = function (dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t) {
        // fuzz-free, array-based Quaternion SLERP operation
        var x0 = src0[srcOffset0 + 0], y0 = src0[srcOffset0 + 1], z0 = src0[srcOffset0 + 2], w0 = src0[srcOffset0 + 3], x1 = src1[srcOffset1 + 0], y1 = src1[srcOffset1 + 1], z1 = src1[srcOffset1 + 2], w1 = src1[srcOffset1 + 3];
        if (w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1) {
            var s = 1 - t, cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, dir = (cos >= 0 ? 1 : -1), sqrSin = 1 - cos * cos;
            // Skip the Slerp for tiny steps to avoid numeric problems:
            if (sqrSin > /*Number.EPSILON*/ 0.0000000000000000001) {
                var sin = Math.sqrt(sqrSin), len = Math.atan2(sin, cos * dir);
                s = Math.sin(s * len) / sin;
                t = Math.sin(t * len) / sin;
            }
            var tDir = t * dir;
            x0 = x0 * s + x1 * tDir;
            y0 = y0 * s + y1 * tDir;
            z0 = z0 * s + z1 * tDir;
            w0 = w0 * s + w1 * tDir;
            // Normalize in case we just did a lerp:
            if (s === 1 - t) {
                var f = 1 / Math.sqrt(x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0);
                x0 *= f;
                y0 *= f;
                z0 *= f;
                w0 *= f;
            }
        }
        dst[dstOffset] = x0;
        dst[dstOffset + 1] = y0;
        dst[dstOffset + 2] = z0;
        dst[dstOffset + 3] = w0;
    };
    Object.defineProperty(Quaternion.prototype, "x", {
        get: function () {
            return this._x;
        },
        set: function (value) {
            this._x = value;
            this.onChangeCallback();
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Quaternion.prototype, "y", {
        get: function () {
            return this._y;
        },
        set: function (value) {
            this._y = value;
            this.onChangeCallback();
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Quaternion.prototype, "z", {
        get: function () {
            return this._z;
        },
        set: function (value) {
            this._z = value;
            this.onChangeCallback();
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Quaternion.prototype, "w", {
        get: function () {
            return this._w;
        },
        set: function (value) {
            this._w = value;
            this.onChangeCallback();
        },
        enumerable: false,
        configurable: true
    });
    Quaternion.prototype.set = function (x, y, z, w) {
        this._x = x;
        this._y = y;
        this._z = z;
        this._w = w;
        this.onChangeCallback();
        return this;
    };
    Quaternion.prototype.clone = function () {
        return new Quaternion(this._x, this._y, this._z, this._w);
    };
    Quaternion.prototype.copy = function (quaternion) {
        this._x = quaternion.x;
        this._y = quaternion.y;
        this._z = quaternion.z;
        this._w = quaternion.w;
        this.onChangeCallback();
        return this;
    };
    Quaternion.prototype.setFromEuler = function (euler, update) {
        var x = euler._x, y = euler._y, z = euler._z, order = euler.order;
        var cos = Math.cos;
        var sin = Math.sin;
        var c1 = cos(x / 2);
        var c2 = cos(y / 2);
        var c3 = cos(z / 2);
        var s1 = sin(x / 2);
        var s2 = sin(y / 2);
        var s3 = sin(z / 2);
        if (order === 'XYZ') {
            this._x = s1 * c2 * c3 + c1 * s2 * s3;
            this._y = c1 * s2 * c3 - s1 * c2 * s3;
            this._z = c1 * c2 * s3 + s1 * s2 * c3;
            this._w = c1 * c2 * c3 - s1 * s2 * s3;
        }
        else if (order === 'YXZ') {
            this._x = s1 * c2 * c3 + c1 * s2 * s3;
            this._y = c1 * s2 * c3 - s1 * c2 * s3;
            this._z = c1 * c2 * s3 - s1 * s2 * c3;
            this._w = c1 * c2 * c3 + s1 * s2 * s3;
        }
        else if (order === 'ZXY') {
            this._x = s1 * c2 * c3 - c1 * s2 * s3;
            this._y = c1 * s2 * c3 + s1 * c2 * s3;
            this._z = c1 * c2 * s3 + s1 * s2 * c3;
            this._w = c1 * c2 * c3 - s1 * s2 * s3;
        }
        else if (order === 'ZYX') {
            this._x = s1 * c2 * c3 - c1 * s2 * s3;
            this._y = c1 * s2 * c3 + s1 * c2 * s3;
            this._z = c1 * c2 * s3 - s1 * s2 * c3;
            this._w = c1 * c2 * c3 + s1 * s2 * s3;
        }
        else if (order === 'YZX') {
            this._x = s1 * c2 * c3 + c1 * s2 * s3;
            this._y = c1 * s2 * c3 + s1 * c2 * s3;
            this._z = c1 * c2 * s3 - s1 * s2 * c3;
            this._w = c1 * c2 * c3 - s1 * s2 * s3;
        }
        else if (order === 'XZY') {
            this._x = s1 * c2 * c3 - c1 * s2 * s3;
            this._y = c1 * s2 * c3 - s1 * c2 * s3;
            this._z = c1 * c2 * s3 + s1 * s2 * c3;
            this._w = c1 * c2 * c3 + s1 * s2 * s3;
        }
        if (update !== false)
            this.onChangeCallback();
        return this;
    };
    Quaternion.prototype.setFromAxisAngle = function (axis, angle) {
        // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
        // assumes axis is normalized
        var halfAngle = angle / 2, s = Math.sin(halfAngle);
        this._x = axis.x * s;
        this._y = axis.y * s;
        this._z = axis.z * s;
        this._w = Math.cos(halfAngle);
        this.onChangeCallback();
        return this;
    };
    Quaternion.prototype.setFromRotationMatrix = function (m) {
        // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
        // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
        var te = m.elements, m11 = te[0], m12 = te[4], m13 = te[8], m21 = te[1], m22 = te[5], m23 = te[9], m31 = te[2], m32 = te[6], m33 = te[10], trace = m11 + m22 + m33, s;
        if (trace > 0) {
            s = 0.5 / Math.sqrt(trace + 1.0);
            this._w = 0.25 / s;
            this._x = (m32 - m23) * s;
            this._y = (m13 - m31) * s;
            this._z = (m21 - m12) * s;
        }
        else if (m11 > m22 && m11 > m33) {
            s = 2.0 * Math.sqrt(1.0 + m11 - m22 - m33);
            this._w = (m32 - m23) / s;
            this._x = 0.25 * s;
            this._y = (m12 + m21) / s;
            this._z = (m13 + m31) / s;
        }
        else if (m22 > m33) {
            s = 2.0 * Math.sqrt(1.0 + m22 - m11 - m33);
            this._w = (m13 - m31) / s;
            this._x = (m12 + m21) / s;
            this._y = 0.25 * s;
            this._z = (m23 + m32) / s;
        }
        else {
            s = 2.0 * Math.sqrt(1.0 + m33 - m11 - m22);
            this._w = (m21 - m12) / s;
            this._x = (m13 + m31) / s;
            this._y = (m23 + m32) / s;
            this._z = 0.25 * s;
        }
        this.onChangeCallback();
        return this;
    };
    Quaternion.prototype.angleTo = function (q) {
        return 2 * Math.acos(Math.abs(clamp(this.dot(q), -1, 1)));
    };
    Quaternion.prototype.rotateTowards = function (q, step) {
        var angle = this.angleTo(q);
        if (angle === 0)
            return this;
        var t = Math.min(1, step / angle);
        this.slerp(q, t);
        return this;
    };
    Quaternion.prototype.inverse = function () {
        // quaternion is assumed to have unit length
        return this.conjugate();
    };
    Quaternion.prototype.conjugate = function () {
        this._x *= -1;
        this._y *= -1;
        this._z *= -1;
        this.onChangeCallback();
        return this;
    };
    Quaternion.prototype.dot = function (v) {
        return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;
    };
    Quaternion.prototype.lengthSq = function () {
        return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
    };
    Quaternion.prototype.length = function () {
        return Math.sqrt(this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w);
    };
    Quaternion.prototype.normalize = function () {
        var l = this.length();
        if (l === 0) {
            this._x = 0;
            this._y = 0;
            this._z = 0;
            this._w = 1;
        }
        else {
            l = 1 / l;
            this._x = this._x * l;
            this._y = this._y * l;
            this._z = this._z * l;
            this._w = this._w * l;
        }
        this.onChangeCallback();
        return this;
    };
    Quaternion.prototype.multiply = function (q, p) {
        if (p !== undefined) {
            console.warn('');
            return this.multiplyQuaternions(q, p);
        }
        return this.multiplyQuaternions(this, q);
    };
    Quaternion.prototype.premultiply = function (q) {
        return this.multiplyQuaternions(q, this);
    };
    Quaternion.prototype.multiplyQuaternions = function (a, b) {
        // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
        var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;
        var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;
        this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
        this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
        this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
        this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
        this.onChangeCallback();
        return this;
    };
    Quaternion.prototype.slerp = function (qb, t) {
        if (t === 0)
            return this;
        if (t === 1)
            return this.copy(qb);
        var x = this._x, y = this._y, z = this._z, w = this._w;
        // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
        var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;
        if (cosHalfTheta < 0) {
            this._w = -qb._w;
            this._x = -qb._x;
            this._y = -qb._y;
            this._z = -qb._z;
            cosHalfTheta = -cosHalfTheta;
        }
        else {
            this.copy(qb);
        }
        if (cosHalfTheta >= 1.0) {
            this._w = w;
            this._x = x;
            this._y = y;
            this._z = z;
            return this;
        }
        var sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta;
        if (sqrSinHalfTheta <= /*Number.EPSILON*/ 0.0000000000001) {
            var s = 1 - t;
            this._w = s * w + t * this._w;
            this._x = s * x + t * this._x;
            this._y = s * y + t * this._y;
            this._z = s * z + t * this._z;
            return this.normalize();
        }
        var sinHalfTheta = Math.sqrt(sqrSinHalfTheta);
        var halfTheta = Math.atan2(sinHalfTheta, cosHalfTheta);
        var ratioA = Math.sin((1 - t) * halfTheta) / sinHalfTheta, ratioB = Math.sin(t * halfTheta) / sinHalfTheta;
        this._w = (w * ratioA + this._w * ratioB);
        this._x = (x * ratioA + this._x * ratioB);
        this._y = (y * ratioA + this._y * ratioB);
        this._z = (z * ratioA + this._z * ratioB);
        this.onChangeCallback();
        return this;
    };
    Quaternion.prototype.equals = function (quaternion) {
        return (quaternion._x === this._x) && (quaternion._y === this._y) && (quaternion._z === this._z) && (quaternion._w === this._w);
    };
    Quaternion.prototype.fromArray = function (array, offset) {
        if (offset === void 0) { offset = 0; }
        this._x = array[offset];
        this._y = array[offset + 1];
        this._z = array[offset + 2];
        this._w = array[offset + 3];
        this.onChangeCallback();
        return this;
    };
    Quaternion.prototype.toArray = function (array, offset) {
        if (array === void 0) { array = []; }
        if (offset === void 0) { offset = 0; }
        array[offset] = this._x;
        array[offset + 1] = this._y;
        array[offset + 2] = this._z;
        array[offset + 3] = this._w;
        return array;
    };
    Quaternion.prototype.onChange = function (callback) {
        this.onChangeCallback = callback;
        return this;
    };
    Quaternion.prototype.onChangeCallback = function () { };
    return Quaternion;
}());

var RotationOrders;
(function (RotationOrders) {
    RotationOrders["XYZ"] = "XYZ";
    RotationOrders["YZX"] = "YZX";
    RotationOrders["ZXY"] = "ZXY";
    RotationOrders["XZY"] = "XZY";
    RotationOrders["YXZ"] = "YXZ";
    RotationOrders["ZYX"] = "ZYX";
})(RotationOrders || (RotationOrders = {}));
var Euler = /** @class */ (function () {
    function Euler(_x, _y, _z, _order) {
        if (_x === void 0) { _x = 0; }
        if (_y === void 0) { _y = 0; }
        if (_z === void 0) { _z = 0; }
        if (_order === void 0) { _order = RotationOrders.XYZ; }
        this._x = _x;
        this._y = _y;
        this._z = _z;
        this._order = _order;
        this.setFromQuaternion = function () {
            var matrix = new Matrix4();
            return function setFromQuaternion(q, order, update) {
                matrix.makeRotationFromQuaternion(q);
                return this.setFromRotationMatrix(matrix, order, update);
            };
        }();
        this.reorder = function () {
            // WARNING: this discards revolution information -bhouston
            var q = new Quaternion();
            return function reorder(newOrder) {
                q.setFromEuler(this);
                return this.setFromQuaternion(q, newOrder);
            };
        }();
    }
    Object.defineProperty(Euler.prototype, "x", {
        get: function () {
            return this._x;
        },
        set: function (value) {
            this._x = value;
            this.onChangeCallback();
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Euler.prototype, "y", {
        get: function () {
            return this._y;
        },
        set: function (value) {
            this._y = value;
            this.onChangeCallback();
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Euler.prototype, "z", {
        get: function () {
            return this._z;
        },
        set: function (value) {
            this._z = value;
            this.onChangeCallback();
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Euler.prototype, "order", {
        get: function () {
            return this._order;
        },
        set: function (value) {
            this._order = value;
            this.onChangeCallback();
        },
        enumerable: false,
        configurable: true
    });
    Euler.prototype.set = function (x, y, z, order) {
        this._x = x;
        this._y = y;
        this._z = z;
        this._order = order || this._order;
        this.onChangeCallback();
        return this;
    };
    Euler.prototype.clone = function () {
        return new Euler(this._x, this._y, this._z, this._order);
    };
    Euler.prototype.copy = function (euler) {
        this._x = euler._x;
        this._y = euler._y;
        this._z = euler._z;
        this._order = euler._order;
        this.onChangeCallback();
        return this;
    };
    Euler.prototype.setFromRotationMatrix = function (m, order, update) {
        // var clamp = _Math.clamp;
        // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
        var te = m.elements;
        var m11 = te[0], m12 = te[4], m13 = te[8];
        var m21 = te[1], m22 = te[5], m23 = te[9];
        var m31 = te[2], m32 = te[6], m33 = te[10];
        order = order || this._order;
        if (order === 'XYZ') {
            this._y = Math.asin(clamp(m13, -1, 1));
            if (Math.abs(m13) < 0.99999) {
                this._x = Math.atan2(-m23, m33);
                this._z = Math.atan2(-m12, m11);
            }
            else {
                this._x = Math.atan2(m32, m22);
                this._z = 0;
            }
        }
        else if (order === 'YXZ') {
            this._x = Math.asin(-clamp(m23, -1, 1));
            if (Math.abs(m23) < 0.99999) {
                this._y = Math.atan2(m13, m33);
                this._z = Math.atan2(m21, m22);
            }
            else {
                this._y = Math.atan2(-m31, m11);
                this._z = 0;
            }
        }
        else if (order === 'ZXY') {
            this._x = Math.asin(clamp(m32, -1, 1));
            if (Math.abs(m32) < 0.99999) {
                this._y = Math.atan2(-m31, m33);
                this._z = Math.atan2(-m12, m22);
            }
            else {
                this._y = 0;
                this._z = Math.atan2(m21, m11);
            }
        }
        else if (order === 'ZYX') {
            this._y = Math.asin(-clamp(m31, -1, 1));
            if (Math.abs(m31) < 0.99999) {
                this._x = Math.atan2(m32, m33);
                this._z = Math.atan2(m21, m11);
            }
            else {
                this._x = 0;
                this._z = Math.atan2(-m12, m22);
            }
        }
        else if (order === 'YZX') {
            this._z = Math.asin(clamp(m21, -1, 1));
            if (Math.abs(m21) < 0.99999) {
                this._x = Math.atan2(-m23, m22);
                this._y = Math.atan2(-m31, m11);
            }
            else {
                this._x = 0;
                this._y = Math.atan2(m13, m33);
            }
        }
        else if (order === 'XZY') {
            this._z = Math.asin(-clamp(m12, -1, 1));
            if (Math.abs(m12) < 0.99999) {
                this._x = Math.atan2(m32, m22);
                this._y = Math.atan2(m13, m11);
            }
            else {
                this._x = Math.atan2(-m23, m33);
                this._y = 0;
            }
        }
        else {
            console.warn('Euler: .setFromRotationMatrix() given unsupported order: ' + order);
        }
        this._order = order;
        if (update !== false)
            this.onChangeCallback();
        return this;
    };
    Euler.prototype.setFromVector3 = function (v, order) {
        return this.set(v.x, v.y, v.z, order || this._order);
    };
    Euler.prototype.equals = function (euler) {
        return (euler._x === this._x) && (euler._y === this._y) && (euler._z === this._z) && (euler._order === this._order);
    };
    Euler.prototype.fromArray = function (array) {
        this._x = array[0];
        this._y = array[1];
        this._z = array[2];
        if (array[3] !== undefined)
            this._order = array[3];
        this.onChangeCallback();
        return this;
    };
    Euler.prototype.toArray = function (array, offset) {
        if (array === undefined)
            array = [];
        if (offset === undefined)
            offset = 0;
        array[offset] = this._x;
        array[offset + 1] = this._y;
        array[offset + 2] = this._z;
        array[offset + 3] = this._order;
        return array;
    };
    Euler.prototype.toVector3 = function (optionalResult) {
        if (optionalResult) {
            return optionalResult.set(this._x, this._y, this._z);
        }
        else {
            return new Vector3(this._x, this._y, this._z);
        }
    };
    Euler.prototype.onChange = function (callback) {
        this.onChangeCallback = callback;
        return this;
    };
    Euler.prototype.onChangeCallback = function () {
    };
    return Euler;
}());

var tempVector3 = new Vector3();
var Object3D = /** @class */ (function (_super) {
    __extends(Object3D, _super);
    function Object3D() {
        var _this = _super.call(this) || this;
        /**
         * 名字
         */
        _this.name = null;
        /**
         * 是否可见
         */
        _this.visible = true;
        _this.mouseEnable = true;
        _this.mouseChildren = true;
        /**
         * 是否投射影子，针对光源和物体
         */
        _this.castShadow = false;
        /**
         * 是否接收影子，针对物体，考虑包括光感与非光感吗？
         */
        _this.receiveShadow = false;
        /**
         * 子级
         */
        _this.children = [];
        /**
         * 父级
         */
        _this.parent = null;
        /**
         * 世界矩阵
         */
        _this._worldMatrix = new Matrix4();
        /**
         * 本地矩阵
         */
        _this._localMatrix = new Matrix4();
        _this.up = Object3D.DefaultUp.clone();
        _this.position = new Vector3();
        _this.scale = new Vector3(1, 1, 1);
        _this._instanceType = "Object3D";
        var rotation = new Euler();
        var quaternion = new Quaternion();
        function onRotationChange() {
            quaternion.setFromEuler(rotation, false);
        }
        function onQuaternionChange() {
            rotation.setFromQuaternion(quaternion, undefined, false);
        }
        rotation.onChange(onRotationChange);
        quaternion.onChange(onQuaternionChange);
        _this.rotation = rotation;
        _this.quaternion = quaternion;
        return _this;
    }
    Object3D.prototype.addChild = function (object) {
        // //是否已添加，不考虑先后渲染了
        // if (this === object.parent) return object;
        // //从原先父级移除自己
        // if (object.parent) object.parent.removeChild(object);
        // object.parent = this;
        // this.children.push(object);
        // //冒泡
        // if (this.scene) object._onDispatchBubbledEvent("onAddedToScene");
        // return object
        this.addChildAt(object, this.children.length);
        return object;
    };
    Object3D.prototype.addChildAt = function (child, index) {
        if (!child)
            return;
        var s = this;
        var sameParent = (s == child.parent);
        var len;
        if (child.parent) {
            if (!sameParent) {
                child.parent.removeChild(child);
            }
            else {
                len = s.children.length;
                for (var i = 0; i < len; i++) {
                    if (s.children[i] == child) {
                        s.children.splice(i, 1);
                        break;
                    }
                }
            }
        }
        child.parent = s;
        len = s.children.length;
        if (index >= len) {
            s.children[s.children.length] = child;
            index = len;
        }
        else if (index == 0 || index < 0) {
            s.children.unshift(child);
            index = 0;
        }
        else {
            s.children.splice(index, 0, child);
        }
        if (s.scene && !sameParent) {
            child._onDispatchBubbledEvent("onAddedToScene");
        }
        return child;
    };
    Object3D.prototype.addChildren = function () {
        var _this = this;
        var children = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            children[_i] = arguments[_i];
        }
        children.forEach(function (child) { _this.addChild(child); });
        return children;
    };
    Object3D.prototype.removeChild = function (object) {
        var index = this.children.indexOf(object);
        if (index !== -1) {
            object.parent = null;
            object._onDispatchBubbledEvent('onRemovedFromScene');
            this.children.splice(index, 1);
        }
        return object;
    };
    /**
     * FYGE. Event得加上属性REMOVED_FROM_SCENE，ADDED_TO_SCENE
     * @param type
     */
    Object3D.prototype._onDispatchBubbledEvent = function (type) {
        var s = this;
        if (type == "onRemovedFromScene" && !s.scene)
            return;
        if (type == "onRemovedFromScene") {
            s.dispatchEvent(type);
            //以防REMOVED_FROM_STAGE事件里用到了scene
            s.scene = null;
        }
        else if (type == "onAddedToScene") {
            s.scene = s.parent.scene;
            s.dispatchEvent(type);
        }
        var len = s.children.length;
        //子级的处理
        for (var i = 0; i < len; i++) {
            s.children[i]._onDispatchBubbledEvent(type);
        }
    };
    Object3D.prototype.clone = function (recursive) {
        if (recursive === void 0) { recursive = true; }
        return new Object3D().copy(this, recursive);
    };
    Object3D.prototype.copy = function (source, recursive) {
        if (recursive === void 0) { recursive = true; }
        this.name = source.name;
        this.visible = source.visible;
        this.up.copy(source.up);
        this.position.copy(source.position);
        this.quaternion.copy(source.quaternion);
        this.scale.copy(source.scale);
        this._localMatrix.copy(source._localMatrix);
        this._worldMatrix.copy(source._worldMatrix);
        this.visible = source.visible;
        if (recursive === true) {
            for (var i = 0; i < source.children.length; i++) {
                var child = source.children[i];
                this.addChild(child.clone());
            }
        }
        return this;
    };
    Object3D.prototype.lookAt = function (x, y, z) {
        var q1 = new Quaternion();
        var m1 = new Matrix4();
        var target = new Vector3();
        var position = new Vector3();
        if (typeof x == "object") {
            target.copy(x);
        }
        else {
            target.set(x, y, z);
        }
        var parent = this.parent;
        this.updateWorldMatrix(true, false);
        position.setFromMatrixPosition(this._worldMatrix);
        if (this._instanceType == "Camera" || this._instanceType == "PerspectiveCamera" || this._instanceType == "OrthographicCamera") {
            m1.lookAt(position, target, this.up);
        }
        else {
            m1.lookAt(target, position, this.up);
        }
        this.quaternion.setFromRotationMatrix(m1);
        if (parent) {
            m1.extractRotation(parent._worldMatrix);
            q1.setFromRotationMatrix(m1);
            this.quaternion.premultiply(q1.inverse());
        }
    };
    Object3D.prototype.applyMatrix = function (matrix) {
        this._localMatrix.multiplyMatrices(matrix, this._localMatrix);
        this._localMatrix.decompose(this.position, this.quaternion, this.scale);
    };
    Object3D.prototype.applyQuaternion = function (q) {
        this.quaternion.premultiply(q);
        return this;
    };
    Object3D.prototype.localToGlobal = function (vector) {
        return vector.applyMatrix4(this._worldMatrix);
    };
    Object3D.prototype.globalToLocal = function (vector) {
        if (vector instanceof Vector3) {
            var m1 = new Matrix4();
            return vector.applyMatrix4(m1.setInverseOf(this._worldMatrix));
        }
        return vector;
    };
    Object.defineProperty(Object3D.prototype, "stagePos", {
        /**
         * 获取该物体的舞台坐标，
         * 其实应该是场景scene3D父级容器中的2d坐标，
         * 如需进一步获取舞台或全局坐标，自行用2d方法继续转换
         */
        get: function () {
            return this.getPosition2d();
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 获取该物体在场景scene3D父级容器中的2d坐标，
     * 如需进一步获取舞台或全局坐标，自行用2d方法继续转换
     * @param {*} vec3 相对自身的3d坐标，存在字段x,y,z的对象，不传表示xyz=0；
     * @returns 返回xy的对象
     */
    Object3D.prototype.getPosition2d = function (vec3) {
        //没有场景返回null
        if (!this.scene)
            return null;
        //不传就是0，0，0
        vec3 = vec3 || { x: 0, y: 0, z: 0 };
        var scene = this.scene;
        this.localToGlobal(tempVector3.copy(vec3));
        tempVector3.project(scene.camera);
        var a = scene.viewWidth / 2;
        var b = scene.viewHeight / 2;
        var x = Math.round(tempVector3.x * a + a) + scene.viewX; //标准设备坐标转屏幕坐标
        var y = Math.round(-tempVector3.y * b + b) + scene.viewY; //标准设备坐标转屏幕坐标
        return { x: x, y: y };
    };
    Object3D.prototype.updateLocalMatrix = function () {
        this._localMatrix.compose(this.position, this.quaternion, this.scale);
        // this.dirty=true
    };
    /**
     * 现在每帧都计算，以后考虑加标记，或手动设置标记更新
     * @param updateParents
     * @param updateChildren
     */
    Object3D.prototype.updateWorldMatrix = function (updateParents, updateChildren) {
        if (updateParents === void 0) { updateParents = false; }
        if (updateChildren === void 0) { updateChildren = true; }
        var parent = this.parent;
        if (updateParents === true && parent !== null) {
            //先往父级递归计算矩阵，判断一次是否2d的父级
            parent.updateWorldMatrix && parent.updateWorldMatrix(true, false);
        }
        //更新本地矩阵先，后续优化加标记
        this.updateLocalMatrix();
        //给出父级的世界矩阵
        if (this.parent === null || !(this.parent instanceof Object3D)) {
            this._worldMatrix.copy(this._localMatrix);
        }
        else {
            this._worldMatrix.multiplyMatrices(this.parent._worldMatrix, this._localMatrix);
        }
        if (updateChildren === true) {
            var children = this.children;
            //往子级递归
            for (var i = 0, l = children.length; i < l; i++)
                children[i].updateWorldMatrix(false, true);
        }
    };
    /**
     * 统一更新方法，子类可重写，基类用于派发监听事件
     */
    Object3D.prototype.update = function () {
        // if (!this.visible) return;//从root往下时block（比如下面子级的visible判断），自身不进行判断
        //监听的
        if (this.hasEventListener(Event.ENTER_FRAME)) {
            this.dispatchEvent(Event.ENTER_FRAME);
        }
        //自己处理
        var len = this.children.length;
        for (var i = len - 1; i >= 0; i--) {
            var child = this.children[i];
            if (child.visible)
                child.update();
        }
    };
    /**
     * 通过名字获取子级
     * @param name
     * @param isOnlyOne
     * @param isRecursive
     */
    Object3D.prototype.getChildByName = function (name, isOnlyOne, isRecursive) {
        if (isOnlyOne === void 0) { isOnlyOne = true; }
        if (isRecursive === void 0) { isRecursive = false; }
        if (!name)
            return null;
        var s = this;
        var rex;
        if (typeof (name) == "string") {
            rex = new RegExp("^" + name + "$");
        }
        else {
            rex = name;
        }
        var elements = [];
        Object3D._getElementsByName(rex, s, isOnlyOne, isRecursive, elements);
        var len = elements.length;
        if (len == 0) {
            return null;
        }
        else if (len == 1) {
            return elements[0];
        }
        else {
            return elements;
        }
    };
    /**
     *
     * @param rex
     * @param root
     * @param isOnlyOne
     * @param isRecursive
     * @param resultList
     */
    Object3D._getElementsByName = function (rex, root, isOnlyOne, isRecursive, resultList) {
        var len = root.children.length;
        if (len > 0) {
            var name = void 0;
            var child = void 0;
            for (var i = 0; i < len; i++) {
                child = root.children[i];
                name = child.name;
                if (name && name != "") {
                    if (rex.test(name)) {
                        resultList[resultList.length] = child;
                        if (isOnlyOne) {
                            return;
                        }
                    }
                }
                if (isRecursive) {
                    if (child["children"] != null) {
                        Object3D._getElementsByName(rex, child, isOnlyOne, isRecursive, resultList);
                    }
                }
            }
        }
    };
    /**
     * 渲染绘制
     */
    Object3D.prototype.render = function (renderer) {
        //自身的渲染
        this._render(renderer);
        //子级的渲染
        for (var i = 0; i < this.children.length; i++) {
            var child = this.children[i];
            if (child.visible)
                child.render(renderer);
        }
    };
    /**
     * 子级重写，自身的渲染方式
     */
    Object3D.prototype._render = function (renderer) {
        //子级重写
        // renderer.batchManager.setObjectRenderer(renderer.plugins["three"]);
        // renderer.plugins["three"].render(this);
    };
    /**
     * 挂个空的吧，只对自己有效，子级的递归，Raycaster方法里已写
     * @param raycaster
     * @param intersects
     */
    Object3D.prototype.raycast = function (raycaster, intersects) {
    };
    Object3D.prototype.destroy = function () {
        //子级的destroy
        for (var i = this.children.length - 1; i >= 0; i--)
            this.children[i].destroy();
        // super.destroy();//不适用继承的，里面的eventTypes置空很麻烦
        //从父级移除自己
        if (this.parent)
            this.parent.removeChild(this);
        //移除事件
        this.removeAllEventListener();
        //还有很多自己的属性，再说了
    };
    Object.defineProperty(Object3D.prototype, "x", {
        ///////////属性get set 方法////////////////////
        /**
         * 位置信息
         */
        get: function () {
            return this.position.x;
        },
        set: function (value) {
            this.position.x = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Object3D.prototype, "y", {
        get: function () {
            return this.position.y;
        },
        set: function (value) {
            this.position.y = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Object3D.prototype, "z", {
        get: function () {
            return this.position.z;
        },
        set: function (value) {
            this.position.z = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Object3D.prototype, "scaleX", {
        /**
         * 缩放信息
         */
        get: function () {
            return this.scale.x;
        },
        set: function (value) {
            this.scale.x = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Object3D.prototype, "scaleY", {
        get: function () {
            return this.scale.y;
        },
        set: function (value) {
            this.scale.y = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Object3D.prototype, "scaleZ", {
        get: function () {
            return this.scale.z;
        },
        set: function (value) {
            this.scale.z = value;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Object3D.prototype, "rotationX", {
        /**
         * 旋转信息，角度制度
         */
        get: function () {
            return this.rotation.x * RAD_TO_DEG;
        },
        /**
         * 角度制
         */
        set: function (value) {
            this.rotation.x = value * DEG_TO_RAD;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Object3D.prototype, "rotationY", {
        /**
         * 旋转信息，角度制度
         */
        get: function () {
            return this.rotation.y * RAD_TO_DEG;
        },
        /**
         * 角度制
         */
        set: function (value) {
            this.rotation.y = value * DEG_TO_RAD;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Object3D.prototype, "rotationZ", {
        /**
         * 旋转信息，角度制度
         */
        get: function () {
            return this.rotation.z * RAD_TO_DEG;
        },
        /**
         * 角度制
         */
        set: function (value) {
            this.rotation.z = value * DEG_TO_RAD;
        },
        enumerable: false,
        configurable: true
    });
    Object3D.DefaultUp = new Vector3(0, 1, 0);
    return Object3D;
}(EventDispatcher));

/**
 * 环境贴图融合方式
 */
var EnvBlendType;
(function (EnvBlendType) {
    EnvBlendType["ENVMAP_BLENDING_MULTIPLY"] = "ENVMAP_BLENDING_MULTIPLY";
    EnvBlendType["ENVMAP_BLENDING_MIX"] = "ENVMAP_BLENDING_MIX";
    EnvBlendType["ENVMAP_BLENDING_ADD"] = "ENVMAP_BLENDING_ADD";
})(EnvBlendType || (EnvBlendType = {}));
var RenderSideType;
(function (RenderSideType) {
    /**
     * 正面才渲染，逆时针顶点
     */
    RenderSideType[RenderSideType["FrontSide"] = 0] = "FrontSide";
    /**
     * 反面才渲染，顺时针顶点顺序
     */
    RenderSideType[RenderSideType["BackSide"] = 1] = "BackSide";
    /**
     * 两面都渲染
     */
    RenderSideType[RenderSideType["DoubleSide"] = 2] = "DoubleSide";
})(RenderSideType || (RenderSideType = {}));
/**
 * 材质基类，一些基本属性加上
 */
var BaseMaterial = /** @class */ (function (_super) {
    __extends(BaseMaterial, _super);
    function BaseMaterial(parameters) {
        var _this = _super.call(this) || this;
        /**
         * 十六进制 hex2rgb ,转成0到1的数组
         */
        _this._color = 0xffffff;
        _this._colorArr = new Float32Array([1.0, 1.0, 1.0]);
        /**
         * 透明度0到1
         */
        _this.alpha = 1;
        _this.combine = EnvBlendType.ENVMAP_BLENDING_MULTIPLY; //环境贴图融合方式，
        _this.reflectivity = 1;
        // public refractionRatio = 0.98;//先只管反射
        // public envMapIntensity = 1.0
        _this.morphTargets = false;
        _this.morphNormals = false;
        _this.skinning = false;
        /**
         * 是否使用顶点颜色
         */
        _this.useVertexColor = false;
        /**
         * 是否用线框形式绘制
         */
        _this.wireframe = false;
        /**
         * 材质渲染面
         */
        _this.side = RenderSideType.FrontSide;
        /**
         * 场景的雾化是否对材质有效
         */
        _this.useFog = true;
        /**
         * 是否光照影响
         */
        _this._lightAffect = false;
        _this._instanceType = "BaseMaterial";
        //所有属性
        if (parameters) {
            for (var key in parameters) {
                _this[key] = parameters[key];
            }
        }
        return _this;
    }
    Object.defineProperty(BaseMaterial.prototype, "color", {
        get: function () {
            return this._color;
        },
        set: function (value) {
            if (this._color === value)
                return;
            this._color = value;
            var arr = hex2rgb$1(value);
            this._colorArr[0] = arr[0];
            this._colorArr[1] = arr[1];
            this._colorArr[2] = arr[2];
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BaseMaterial.prototype, "colorArr", {
        //获取
        get: function () {
            return this._colorArr;
        },
        enumerable: false,
        configurable: true
    });
    BaseMaterial.prototype.copy = function (material) {
        this.color = material.color;
        this.map = material.map;
        this.alpha = material.alpha;
        this.morphTargets = material.morphTargets;
        this.morphNormals = material.morphNormals;
        this.skinning = material.skinning;
        this.wireframe = material.wireframe;
        this.side = material.side;
        this._lightAffect = material._lightAffect;
        return this;
    };
    BaseMaterial.prototype.clone = function () {
        return new BaseMaterial().copy(this);
    };
    BaseMaterial.prototype.destroy = function () {
        this._color = null;
    };
    return BaseMaterial;
}(HashObject));

var Ray = /** @class */ (function () {
    function Ray(origin, direction) {
        if (origin === void 0) { origin = new Vector3(); }
        if (direction === void 0) { direction = new Vector3(); }
        this.origin = origin;
        this.direction = direction;
    }
    Ray.prototype.set = function (origin, direction) {
        this.origin.copy(origin);
        this.direction.copy(direction);
        return this;
    };
    Ray.prototype.clone = function () {
        return new Ray().copy(this);
    };
    Ray.prototype.copy = function (ray) {
        this.origin.copy(ray.origin);
        this.direction.copy(ray.direction);
        return this;
    };
    Ray.prototype.at = function (t, target) {
        return target.copy(this.direction).multiplyScalar(t).add(this.origin);
    };
    Ray.prototype.lookAt = function (v) {
        this.direction.copy(v).sub(this.origin).normalize();
        return this;
    };
    Ray.prototype.recast = function (t) {
        var v1 = new Vector3();
        this.origin.copy(this.at(t, v1));
        return this;
    };
    Ray.prototype.closestPointToPoint = function (point, out) {
        if (out === void 0) { out = new Vector3(); }
        out.subVectors(point, this.origin);
        var directionDistance = out.dot(this.direction);
        if (directionDistance < 0)
            return out.copy(this.origin);
        return out.copy(this.direction).multiplyScalar(directionDistance).add(this.origin);
    };
    Ray.prototype.distanceToPoint = function (point) {
        return Math.sqrt(this.distanceSqToPoint(point));
    };
    Ray.prototype.distanceSqToPoint = function (point) {
        var v1 = new Vector3();
        var directionDistance = v1.subVectors(point, this.origin).dot(this.direction);
        // point behind the ray
        if (directionDistance < 0) {
            return this.origin.distanceToSquared(point);
        }
        v1.copy(this.direction).multiplyScalar(directionDistance).add(this.origin);
        return v1.distanceToSquared(point);
    };
    Ray.prototype.intersectSphere = function (sphere, out) {
        var v1 = new Vector3();
        v1.subVectors(sphere.center, this.origin);
        var tca = v1.dot(this.direction);
        var d2 = v1.dot(v1) - tca * tca;
        var radius2 = sphere.radius * sphere.radius;
        if (d2 > radius2)
            return null;
        var thc = Math.sqrt(radius2 - d2);
        // t0 = first intersect point - entrance on front of sphere
        var t0 = tca - thc;
        // t1 = second intersect point - exit point on back of sphere
        var t1 = tca + thc;
        // test to see if both t0 and t1 are behind the ray - if so, return null
        if (t0 < 0 && t1 < 0)
            return null;
        // test to see if t0 is behind the ray:
        // if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
        // in order to always return an intersect point that is in front of the ray.
        if (t0 < 0)
            return this.at(t1, out);
        // else t0 is in front of the ray, so return the first collision point scaled by t0
        return this.at(t0, out);
    };
    Ray.prototype.intersectsSphere = function (sphere) {
        return this.distanceSqToPoint(sphere.center) <= (sphere.radius * sphere.radius);
    };
    Ray.prototype.intersectBox = function (box, out) {
        var tmin, tmax, tymin, tymax, tzmin, tzmax;
        var invdirx = 1 / this.direction.x, invdiry = 1 / this.direction.y, invdirz = 1 / this.direction.z;
        var origin = this.origin;
        if (invdirx >= 0) {
            tmin = (box.min.x - origin.x) * invdirx;
            tmax = (box.max.x - origin.x) * invdirx;
        }
        else {
            tmin = (box.max.x - origin.x) * invdirx;
            tmax = (box.min.x - origin.x) * invdirx;
        }
        if (invdiry >= 0) {
            tymin = (box.min.y - origin.y) * invdiry;
            tymax = (box.max.y - origin.y) * invdiry;
        }
        else {
            tymin = (box.max.y - origin.y) * invdiry;
            tymax = (box.min.y - origin.y) * invdiry;
        }
        if ((tmin > tymax) || (tymin > tmax))
            return null;
        // These lines also handle the case where tmin or tmax is NaN
        // (result of 0 * Infinity). x !== x returns true if x is NaN
        if (tymin > tmin || tmin !== tmin)
            tmin = tymin;
        if (tymax < tmax || tmax !== tmax)
            tmax = tymax;
        if (invdirz >= 0) {
            tzmin = (box.min.z - origin.z) * invdirz;
            tzmax = (box.max.z - origin.z) * invdirz;
        }
        else {
            tzmin = (box.max.z - origin.z) * invdirz;
            tzmax = (box.min.z - origin.z) * invdirz;
        }
        if ((tmin > tzmax) || (tzmin > tmax))
            return null;
        if (tzmin > tmin || tmin !== tmin)
            tmin = tzmin;
        if (tzmax < tmax || tmax !== tmax)
            tmax = tzmax;
        //return point closest to the ray (positive side)
        if (tmax < 0)
            return null;
        return this.at(tmin >= 0 ? tmin : tmax, out);
    };
    Ray.prototype.intersectsBox = function (box) {
        return this.intersectBox(box, new Vector3()) !== null;
    };
    Ray.prototype.intersectTriangle = function (a, b, c, backfaceCulling, out) {
        // Compute the offset origin, edges, and normal.
        var diff = new Vector3();
        var edge1 = new Vector3();
        var edge2 = new Vector3();
        var normal = new Vector3();
        // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h
        edge1.subVectors(b, a);
        edge2.subVectors(c, a);
        normal.crossVectors(edge1, edge2);
        // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
        // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
        //   |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
        //   |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
        //   |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
        var DdN = this.direction.dot(normal);
        var sign;
        if (DdN > 0) {
            if (backfaceCulling)
                return null;
            sign = 1;
        }
        else if (DdN < 0) {
            sign = -1;
            DdN = -DdN;
        }
        else {
            return null;
        }
        diff.subVectors(this.origin, a);
        var DdQxE2 = sign * this.direction.dot(edge2.crossVectors(diff, edge2));
        // b1 < 0, no intersection
        if (DdQxE2 < 0) {
            return null;
        }
        var DdE1xQ = sign * this.direction.dot(edge1.cross(diff));
        // b2 < 0, no intersection
        if (DdE1xQ < 0) {
            return null;
        }
        // b1+b2 > 1, no intersection
        if (DdQxE2 + DdE1xQ > DdN) {
            return null;
        }
        // Line intersects triangle, check if ray does.
        var QdN = -sign * diff.dot(normal);
        // t < 0, no intersection
        if (QdN < 0) {
            return null;
        }
        // Ray intersects triangle.
        return this.at(QdN / DdN, out);
    };
    Ray.prototype.applyMatrix4 = function (matrix4) {
        this.origin.applyMatrix4(matrix4);
        this.direction.transformDirection(matrix4);
        return this;
    };
    Ray.prototype.equals = function (ray) {
        return ray.origin.equals(this.origin) && ray.direction.equals(this.direction);
    };
    return Ray;
}());
// function vec3Cross(v1, v2) {
//     v1 = v1.elements;
//     v2 = v2.elements;
//     return new Vector3([
//         v1[1] * v2[2] - v1[2] * v2[1],
//         v1[2] * v2[0] - v1[0] * v2[2],
//         v1[0] * v2[1] - v1[1] * v2[0],
//     ])
// }
// function vec3Sub(v1, v2) {
//     v1 = v1.elements;
//     v2 = v2.elements
//     return new Vector3([v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2]]);
// }
// function vec3Dot(v1, v2) {
//     v1 = v1.elements;
//     v2 = v2.elements
//     return v1[0] * v2[0] + v1[1] + v2[1] + v1[2] + v2[2];
// }
// // Determine whether a ray intersect with a triangle
// // Parameters
// // orig: origin of the ray
// // dir: direction of the ray
// // v0, v1, v2: vertices of triangle
// // t(out): weight of the intersection for the ray
// // u(out), v(out): barycentric coordinate of intersection
// function intersectTriangle(orig, dir, v0, v1, v2) {
//     let t, u, v;
//     // E1
//     const E1 = vec3Sub(v1, v0);
//     // E2
//     const E2 = vec3Sub(v2, v0);
//     // P
//     const P = vec3Cross(dir, E2);
//     // determinant
//     let det = vec3Dot(E1, P);
//     // keep det > 0, modify T accordingly
//     let T;
//     if (det > 0) {
//         T = vec3Sub(orig, v0);
//     } else {
//         T = vec3Sub(v0, orig);
//         det = -det;
//     }
//     // If determinant is near zero, ray lies in plane of triangle
//     if (det < 0.0001) return false;
//     // Calculate u and make sure u <= 1
//     u = vec3Dot(T, P);
//     if (u < 0.0 || u > det) return false;
//     // Q
//     const Q = vec3Cross(T, E1);
//     // Calculate v and make sure u + v <= 1
//     v = vec3Dot(dir, Q);
//     if (v < 0.0 || u + v > det) return false;
//     // Calculate t, scale parameters, ray intersects triangle
//     t = vec3Dot(E2, Q);
//     const fInvDet = 1.0 / det;
//     t *= fInvDet;
//     u *= fInvDet;
//     v *= fInvDet;
//     console.log(t, u, v);
//     return true;
// }
// const intersect = intersectTriangle(
//     new Vector3([0, 0, 0]), new Vector3([0, 0, 1]),
//     new Vector3([-1, 1, 1]),
//     new Vector3([1, 1, 1]),
//     new Vector3([0, -1, 1]),
// );
// console.log(intersect);

var Box3 = /** @class */ (function () {
    function Box3(min, max) {
        if (min === void 0) { min = new Vector3(+Infinity, +Infinity, +Infinity); }
        if (max === void 0) { max = new Vector3(-Infinity, -Infinity, -Infinity); }
        this.min = min;
        this.max = max;
    }
    Box3.prototype.set = function (min, max) {
        this.min.copy(min);
        this.max.copy(max);
        return this;
    };
    Box3.prototype.clone = function () {
        return new Box3().copy(this);
    };
    Box3.prototype.copy = function (box) {
        this.min.copy(box.min);
        this.max.copy(box.max);
        return this;
    };
    Box3.prototype.makeEmpty = function () {
        this.min.x = this.min.y = this.min.z = +Infinity;
        this.max.x = this.max.y = this.max.z = -Infinity;
        return this;
    };
    Box3.prototype.isEmpty = function () {
        return (this.max.x < this.min.x) || (this.max.y < this.min.y) || (this.max.z < this.min.z);
    };
    /**
     * 获取中心点
     * @param out
     */
    Box3.prototype.getCenter = function (out) {
        if (out === void 0) { out = new Vector3(); }
        return this.isEmpty() ? out.set(0, 0, 0) : out.addVectors(this.min, this.max).multiplyScalar(0.5);
    };
    /**
     * 获取对角线向量
     * @param out
     */
    Box3.prototype.getSize = function (out) {
        if (out === void 0) { out = new Vector3(); }
        return this.isEmpty() ? out.set(0, 0, 0) : out.subVectors(this.max, this.min);
    };
    /**
     *
     * @param array 一般是顶点一维数组
     */
    Box3.prototype.setFromArray = function (array) {
        var minX = +Infinity;
        var minY = +Infinity;
        var minZ = +Infinity;
        var maxX = -Infinity;
        var maxY = -Infinity;
        var maxZ = -Infinity;
        for (var i = 0, l = array.length; i < l; i += 3) {
            var x = array[i];
            var y = array[i + 1];
            var z = array[i + 2];
            if (x < minX)
                minX = x;
            if (y < minY)
                minY = y;
            if (z < minZ)
                minZ = z;
            if (x > maxX)
                maxX = x;
            if (y > maxY)
                maxY = y;
            if (z > maxZ)
                maxZ = z;
        }
        this.min.set(minX, minY, minZ);
        this.max.set(maxX, maxY, maxZ);
        return this;
    };
    Box3.prototype.setFromCenterAndSize = function (center, size) {
        var v1 = new Vector3();
        var halfSize = v1.copy(size).multiplyScalar(0.5);
        this.min.copy(center).sub(halfSize);
        this.max.copy(center).add(halfSize);
        return this;
    };
    Box3.prototype.setFromPoints = function (points) {
        this.makeEmpty();
        for (var i = 0, il = points.length; i < il; i++) {
            this.expandByPoint(points[i]);
        }
        return this;
    };
    Box3.prototype.setFromObject = function (object) {
        this.makeEmpty();
        return this.expandByObject(object);
    };
    /**
     * 为了包含该点坐标
     * @param point
     */
    Box3.prototype.expandByPoint = function (point) {
        this.min.min(point);
        this.max.max(point);
        return this;
    };
    /**
     * 为了xyz分别根据vector进行扩展
     * @param vector
     */
    Box3.prototype.expandByVector = function (vector) {
        this.min.sub(vector);
        this.max.add(vector);
        return this;
    };
    Box3.prototype.expandByScalar = function (scalar) {
        this.min.addScalar(-scalar);
        this.max.addScalar(scalar);
        return this;
    };
    Box3.prototype.expandByObject = function (object) {
        var scope = this;
        var v1 = new Vector3();
        object.updateWorldMatrix();
        traverse(object);
        function traverse(node) {
            //@ts-ignore 自己的先算
            var geometry = node.geometry;
            if (geometry !== undefined && geometry._vertices) {
                var vertices = geometry._vertices;
                for (var i = 0; i < vertices.length; i += 3) {
                    v1.set(vertices[i], vertices[i + 1], vertices[i + 2]).applyMatrix4(node._worldMatrix);
                    scope.expandByPoint(v1);
                }
            }
            //子级递归
            for (var j = 0; j < node.children.length; j++)
                traverse(node.children[j]);
        }
        return scope;
    };
    Box3.prototype.containsPoint = function (point) {
        return point.x < this.min.x || point.x > this.max.x ||
            point.y < this.min.y || point.y > this.max.y ||
            point.z < this.min.z || point.z > this.max.z ? false : true;
    };
    Box3.prototype.containsBox = function (box) {
        return this.min.x <= box.min.x && box.max.x <= this.max.x &&
            this.min.y <= box.min.y && box.max.y <= this.max.y &&
            this.min.z <= box.min.z && box.max.z <= this.max.z;
    };
    Box3.prototype.intersectsBox = function (box) {
        return box.max.x < this.min.x || box.min.x > this.max.x ||
            box.max.y < this.min.y || box.min.y > this.max.y ||
            box.max.z < this.min.z || box.min.z > this.max.z ? false : true;
    };
    Box3.prototype.intersectsSphere = function (sphere) {
        var closestPoint = new Vector3();
        // Find the point on the AABB closest to the sphere center.
        this.clampPoint(sphere.center, closestPoint);
        // If that point is inside the sphere, the AABB and sphere intersect.
        return closestPoint.distanceToSquared(sphere.center) <= (sphere.radius * sphere.radius);
    };
    Box3.prototype.clampPoint = function (point, out) {
        if (out === void 0) { out = new Vector3(); }
        return out.copy(point).clamp(this.min, this.max);
    };
    Box3.prototype.distanceToPoint = function (point) {
        var v1 = new Vector3();
        var clampedPoint = v1.copy(point).clamp(this.min, this.max);
        return clampedPoint.sub(point).length();
    };
    Box3.prototype.getBoundingSphere = function (out) {
        if (out === void 0) { out = new Sphere(); }
        var v1 = new Vector3();
        this.getCenter(out.center);
        out.radius = this.getSize(v1).length() * 0.5;
        return out;
    };
    Box3.prototype.intersect = function (box) {
        this.min.max(box.min);
        this.max.min(box.max);
        // ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values.
        if (this.isEmpty())
            this.makeEmpty();
        return this;
    };
    Box3.prototype.union = function (box) {
        this.min.min(box.min);
        this.max.max(box.max);
        return this;
    };
    Box3.prototype.applyMatrix4 = function (matrix) {
        var points = [
            new Vector3(),
            new Vector3(),
            new Vector3(),
            new Vector3(),
            new Vector3(),
            new Vector3(),
            new Vector3(),
            new Vector3()
        ];
        // transform of empty box is an empty box.
        if (this.isEmpty())
            return this;
        // NOTE: I am using a binary pattern to specify all 2^3 combinations below
        points[0].set(this.min.x, this.min.y, this.min.z).applyMatrix4(matrix); // 000
        points[1].set(this.min.x, this.min.y, this.max.z).applyMatrix4(matrix); // 001
        points[2].set(this.min.x, this.max.y, this.min.z).applyMatrix4(matrix); // 010
        points[3].set(this.min.x, this.max.y, this.max.z).applyMatrix4(matrix); // 011
        points[4].set(this.max.x, this.min.y, this.min.z).applyMatrix4(matrix); // 100
        points[5].set(this.max.x, this.min.y, this.max.z).applyMatrix4(matrix); // 101
        points[6].set(this.max.x, this.max.y, this.min.z).applyMatrix4(matrix); // 110
        points[7].set(this.max.x, this.max.y, this.max.z).applyMatrix4(matrix); // 111
        this.setFromPoints(points);
        return this;
    };
    Box3.prototype.translate = function (offset) {
        this.min.add(offset);
        this.max.add(offset);
        return this;
    };
    Box3.prototype.equals = function (box) {
        return box.min.equals(this.min) && box.max.equals(this.max);
    };
    return Box3;
}());

var Sphere = /** @class */ (function () {
    function Sphere(center, radius) {
        if (center === void 0) { center = new Vector3(); }
        if (radius === void 0) { radius = 0; }
        this.center = center;
        this.radius = radius;
    }
    Sphere.prototype.set = function (center, radius) {
        this.center.copy(center);
        this.radius = radius;
        return this;
    };
    Sphere.prototype.setFromPoints = function (points, optionalCenter) {
        var box = new Box3();
        var center = this.center;
        if (optionalCenter !== undefined) {
            center.copy(optionalCenter);
        }
        else {
            box.setFromPoints(points).getCenter(center);
        }
        var maxRadiusSq = 0;
        for (var i = 0, il = points.length; i < il; i++) {
            maxRadiusSq = Math.max(maxRadiusSq, center.distanceToSquared(points[i]));
        }
        this.radius = Math.sqrt(maxRadiusSq);
        return this;
    };
    Sphere.prototype.clone = function () {
        return new Sphere().copy(this);
    };
    Sphere.prototype.copy = function (sphere) {
        this.center.copy(sphere.center);
        this.radius = sphere.radius;
        return this;
    };
    Sphere.prototype.empty = function () {
        return (this.radius <= 0);
    };
    Sphere.prototype.containsPoint = function (point) {
        return (point.distanceToSquared(this.center) <= (this.radius * this.radius));
    };
    Sphere.prototype.distanceToPoint = function (point) {
        return (point.distanceTo(this.center) - this.radius);
    };
    Sphere.prototype.intersectsSphere = function (sphere) {
        var radiusSum = this.radius + sphere.radius;
        return sphere.center.distanceToSquared(this.center) <= (radiusSum * radiusSum);
    };
    Sphere.prototype.intersectsBox = function (box) {
        return box.intersectsSphere(this);
    };
    Sphere.prototype.clampPoint = function (point, target) {
        if (target === void 0) { target = new Vector3(); }
        var deltaLengthSq = this.center.distanceToSquared(point);
        target.copy(point);
        if (deltaLengthSq > (this.radius * this.radius)) {
            target.sub(this.center).normalize();
            target.multiplyScalar(this.radius).add(this.center);
        }
        return target;
    };
    Sphere.prototype.getBoundingBox = function (target) {
        if (target === void 0) { target = new Box3(); }
        target.set(this.center, this.center);
        target.expandByScalar(this.radius);
        return target;
    };
    Sphere.prototype.applyMatrix4 = function (matrix) {
        this.center.applyMatrix4(matrix);
        this.radius = this.radius * matrix.getMaxScaleOnAxis();
        return this;
    };
    Sphere.prototype.translate = function (offset) {
        this.center.add(offset);
        return this;
    };
    Sphere.prototype.equals = function (sphere) {
        return sphere.center.equals(this.center) && (sphere.radius === this.radius);
    };
    return Sphere;
}());

var templeSphere = new Sphere();
var tempMatrix = new Matrix4();
var tempRay = new Ray();
var tempPoint = new Vector3();
//现在基本所有3d的显示对象(sprite3d以及所有help)都继承自Mesh3D，但是以后尽量分开，包括line和point，以及材质也需要分开，TODO
var Mesh3D = /** @class */ (function (_super) {
    __extends(Mesh3D, _super);
    //这个暂时不知道有啥用，到时看three的
    // morphTargetDictionary
    function Mesh3D(geometry, material) {
        var _this = _super.call(this) || this;
        _this.geometry = geometry;
        _this.material = material;
        _this._instanceType = "Mesh3D";
        _this.updateMorphTargets();
        return _this;
    }
    Object.defineProperty(Mesh3D.prototype, "morphTargetInfluences", {
        get: function () {
            return this._morphTargetInfluences;
        },
        enumerable: false,
        configurable: true
    });
    Mesh3D.prototype._render = function (renderer) {
        if (!this.visible || !this.material.alpha)
            return; //到时加transparent时需要修改 TODO
        renderer.batchManager.setObjectRenderer(renderer.plugins["d3"]);
        renderer.plugins["d3"].render(this);
    };
    Mesh3D.prototype.updateMorphTargets = function () {
        var morphPositions = this.geometry._morphPositions;
        if (morphPositions) {
            this._morphTargetInfluences = [];
            //根据morphPositions的长度来定权重长度
            for (var i = 0; i < morphPositions.length; i++)
                this._morphTargetInfluences.push(0);
        }
    };
    Mesh3D.prototype.raycast = function (raycaster, intersects) {
        if (!this.visible || !this.geometry || !this.material || this.material.wireframe)
            return;
        var geometry = this.geometry;
        var matrixWorld = this._worldMatrix;
        // Checking boundingSphere distance to ray
        if (!geometry.boundingSphere)
            geometry.computeBoundingSphere();
        templeSphere.copy(geometry.boundingSphere);
        templeSphere.applyMatrix4(matrixWorld);
        if (raycaster.ray.intersectsSphere(templeSphere) === false)
            return;
        //
        tempMatrix.setInverseOf(matrixWorld);
        tempRay.copy(raycaster.ray).applyMatrix4(tempMatrix);
        // Check boundingBox before continuing
        if (geometry.boundingBox !== null && tempRay.intersectsBox(geometry.boundingBox) === false)
            return;
        //如果不需要面检测，到此为止了
        if (!geometry.doHitFace) {
            // raycaster.ray.origin.distanceTo(templeSphere.center) - templeSphere.radius,
            intersects.push({
                distance: raycaster.ray.origin.distanceTo(templeSphere.center) - templeSphere.radius,
                object: this
            });
            return;
        }
        var intersection;
        var a = new Vector3(), b = new Vector3(), c = new Vector3();
        var index = geometry._indices;
        var position = geometry._vertices;
        if (index) {
            for (var i = 0; i < index.length; i += 3) {
                var i1 = index[i], i2 = index[i + 1], i3 = index[i + 2];
                a.set(position[i1 * 3], position[i1 * 3 + 1], position[i1 * 3 + 2]);
                b.set(position[i2 * 3], position[i2 * 3 + 1], position[i2 * 3 + 2]);
                c.set(position[i3 * 3], position[i3 * 3 + 1], position[i3 * 3 + 2]);
                intersection = checkIntersection(this, raycaster, tempRay, a, b, c, tempPoint);
                if (intersection) { //有一个就出
                    intersects.push(intersection);
                    break;
                }
            }
        }
        else if (position) {
            for (var i = 0; i < position.length; i += 9) {
                a.set(position[i], position[i + 1], position[i + 2]);
                b.set(position[i + 3], position[i + 4], position[i + 5]);
                c.set(position[i + 6], position[i + 7], position[i + 8]);
                intersection = checkIntersection(this, raycaster, tempRay, a, b, c, tempPoint);
                if (intersection) { //有一个就出
                    intersects.push(intersection);
                    break;
                }
            }
        }
    };
    Mesh3D.prototype.copy = function (source, recursive) {
        if (recursive === void 0) { recursive = true; }
        _super.prototype.copy.call(this, source, recursive);
        if (source.morphTargetInfluences) { //变形的数据
            this._morphTargetInfluences = source.morphTargetInfluences.slice();
        }
        //暂时不用
        // if ( source.morphTargetDictionary !== undefined ) {
        // 	this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary );
        // }
        return this;
    };
    /**
     * 克隆方法
     * @param recursive 默认克隆子级
     */
    Mesh3D.prototype.clone = function (recursive) {
        if (recursive === void 0) { recursive = true; }
        return new Mesh3D(this.geometry, this.material).copy(this, recursive);
    };
    return Mesh3D;
}(Object3D));
var intersectionPointWorld = new Vector3();
function checkIntersection(object, raycaster, ray, pA, pB, pC, point) {
    var material = object.material;
    var intersect;
    if (material.side === RenderSideType.BackSide) {
        intersect = ray.intersectTriangle(pC, pB, pA, true, point);
    }
    else {
        intersect = ray.intersectTriangle(pA, pB, pC, material.side !== RenderSideType.DoubleSide, point);
    }
    if (intersect === null)
        return null;
    intersectionPointWorld.copy(point);
    intersectionPointWorld.applyMatrix4(object._worldMatrix);
    var distance = raycaster.ray.origin.distanceTo(intersectionPointWorld);
    if (distance < raycaster.near || distance > raycaster.far)
        return null;
    return {
        distance: distance,
        point: intersectionPointWorld.clone(),
        object: object
    };
}

/**
 * 考虑需要记录哪些几何数据
 * 暂时都在构造中执行一次数据的赋值，如果以后涉及需要动态修改数据的，加标记修改，插件里也需要重新upload数据
 * 到时改成对象记录所有attribute。仿three，但是vao还会存在，但是会检查是否更新
 * 感觉东西越来越多，迟早得换成three的方式，到时还要考虑数据要修改的情况，否则做游戏蛋疼，现在不改是担心改了后性能出问题，
 */
var Geometry = /** @class */ (function (_super) {
    __extends(Geometry, _super);
    /**
     *
     * @param vertices
     * @param indices
     * @param normals
     * @param colors
     * @param uvs
     */
    function Geometry(vertices, indices, normals, colors, uvs) {
        var _this = _super.call(this) || this;
        /**
         * 顶点坐标3，颜色3，uv2，法线3，到时还是搞成three的那种方式，多属性对象，统一放到vao上
         */
        _this._vertByteSize = (3 + 3 + 2 + 3) * 4;
        //记录上面四项数据是否修改了，自行赋值
        _this.attrBufferNeedUpdate = false;
        _this.boundingBox = null;
        _this.boundingSphere = null;
        /**
         * 是否按面检测
         */
        _this.doHitFace = false;
        _this._instanceType = "Geometry";
        _this._glVaoBuffer = {};
        //_vertices，_normals，_colors，_uvs正常数字数组也行，反正会取出来放到_attrBuffer里
        _this._vertices = vertices;
        _this._normals = normals || new Float32Array(vertices.length);
        _this._colors = colors || (function () {
            var f = new Float32Array(vertices.length);
            for (var i = 0; i < vertices.length; i++)
                f[i] = 1;
            return f;
        })(); //new Float32Array(vertices.length).map(() => { return 1 });//不传就全是白色
        _this._uvs = uvs || new Float32Array(vertices.length / 3 * 2);
        //索引直接用，可能没有，需要转成类型化数组，会直接upload
        _this._indices = indices ? new Uint16Array(indices) : null;
        return _this;
        //顶点长度先记录，渲染时再加了，先去掉
        // this._attrBuffer = new BatchBuffer(vertices.length / 3 * this._vertByteSize);
    }
    Geometry.prototype.computeBoundingBox = function () {
        if (!this.boundingBox)
            this.boundingBox = new Box3();
        var position = this._vertices;
        if (position) {
            this.boundingBox.setFromArray(position);
        }
        else {
            this.boundingBox.makeEmpty();
        }
        if (isNaN(this.boundingBox.min.x) || isNaN(this.boundingBox.min.y) || isNaN(this.boundingBox.min.z))
            console.error("error vertices data");
    };
    Geometry.prototype.computeBoundingSphere = function () {
        var box = new Box3();
        var vector = new Vector3();
        if (!this.boundingSphere)
            this.boundingSphere = new Sphere();
        var position = this._vertices;
        if (position) {
            var center = this.boundingSphere.center;
            box.setFromArray(position);
            box.getCenter(center);
            // hoping to find a boundingSphere with a radius smaller than the
            // boundingSphere of the boundingBox: sqrt(3) smaller in the best case
            var maxRadiusSq = 0;
            for (var i = 0, il = position.length; i < il; i += 3) {
                vector.x = position[i];
                vector.y = position[i + 1];
                vector.z = position[i + 2];
                maxRadiusSq = Math.max(maxRadiusSq, center.distanceToSquared(vector));
            }
            this.boundingSphere.radius = Math.sqrt(maxRadiusSq);
            if (isNaN(this.boundingSphere.radius))
                console.error("error vertices data");
        }
    };
    // copy(){
    // }
    // clone(){}
    Geometry.prototype.destroy = function () {
    };
    return Geometry;
}(HashObject));
// var vertices = new Float32Array([
//     2.0, 2.0, 2.0, -2.0, 2.0, 2.0, -2.0, -2.0, 2.0, 2.0, -2.0, 2.0, // v0-v1-v2-v3 front
//     2.0, 2.0, 2.0, 2.0, -2.0, 2.0, 2.0, -2.0, -2.0, 2.0, 2.0, -2.0, // v0-v3-v4-v5 right
//     2.0, 2.0, 2.0, 2.0, 2.0, -2.0, -2.0, 2.0, -2.0, -2.0, 2.0, 2.0, // v0-v5-v6-v1 up
//     -2.0, 2.0, 2.0, -2.0, 2.0, -2.0, -2.0, -2.0, -2.0, -2.0, -2.0, 2.0, // v1-v6-v7-v2 left
//     -2.0, -2.0, -2.0, 2.0, -2.0, -2.0, 2.0, -2.0, 2.0, -2.0, -2.0, 2.0, // v7-v4-v3-v2 down
//     2.0, -2.0, -2.0, -2.0, -2.0, -2.0, -2.0, 2.0, -2.0, 2.0, 2.0, -2.0  // v4-v7-v6-v5 back
// ]);
// var colors = new Float32Array([    // Colors
//     1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,     // v0-v1-v2-v3 front
//     1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,     // v0-v3-v4-v5 right
//     1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,     // v0-v5-v6-v1 up
//     1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,     // v1-v6-v7-v2 left
//     1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,     // v7-v4-v3-v2 down
//     1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0　    // v4-v7-v6-v5 back
// ]);
// colors = colors.map(() => {
//     return 1
// })
// var normals = new Float32Array([    // Normal
//     0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0,  // v0-v1-v2-v3 front
//     1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0,  // v0-v3-v4-v5 right
//     0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,  // v0-v5-v6-v1 up
//     -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0,  // v1-v6-v7-v2 left
//     0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0,  // v7-v4-v3-v2 down
//     0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0   // v4-v7-v6-v5 back
// ]);
// var uvs = new Float32Array([
//     1.0, 1.0,
//     0.0, 1.0,
//     0.0, 0.0,
//     1.0, 0.0,
//     1.0, 1.0,
//     0.0, 1.0,
//     0.0, 0.0,
//     1.0, 0.0,
//     1.0, 1.0,
//     0.0, 1.0,
//     0.0, 0.0,
//     1.0, 0.0,
//     1.0, 1.0,
//     0.0, 1.0,
//     0.0, 0.0,
//     1.0, 0.0,
//     1.0, 1.0,
//     0.0, 1.0,
//     0.0, 0.0,
//     1.0, 0.0,
//     1.0, 1.0,
//     0.0, 1.0,
//     0.0, 0.0,
//     1.0, 0.0,
// ]);
// var indices = new Uint16Array([       // Indices of the vertices
//     0, 1, 2, 0, 2, 3,    // front
//     4, 5, 6, 4, 6, 7,    // right
//     8, 9, 10, 8, 10, 11,    // up
//     12, 13, 14, 12, 14, 15,    // left
//     16, 17, 18, 16, 18, 19,    // down
//     20, 21, 22, 20, 22, 23     // back
// ]);

var Camera = /** @class */ (function (_super) {
    __extends(Camera, _super);
    function Camera() {
        var _this = _super.call(this) || this;
        _this._instanceType = 'Camera';
        _this.worldMatrixInverse = new Matrix4();
        _this.projectionMatrix = new Matrix4();
        _this.projectionMatrixInverse = new Matrix4();
        return _this;
    }
    /**
     * 重写
     * @param recursive
     */
    Camera.prototype.clone = function () {
        return new Camera().copy(this);
    };
    Camera.prototype.copy = function (source, recursive) {
        _super.prototype.copy.call(this, source, recursive);
        // Object3D.prototype.copy.call(this, source, recursive);
        this.worldMatrixInverse.copy(source.matrixWorldInverse);
        this.projectionMatrix.copy(source.projectionMatrix);
        this.projectionMatrixInverse.copy(source.projectionMatrixInverse);
        return this;
    };
    Camera.prototype.getWorldDirection = function (target) {
        this.updateWorldMatrix();
        var e = this._worldMatrix.elements;
        return target.set(-e[8], -e[9], -e[10]).normalize();
    };
    Camera.prototype.updateWorldMatrix = function () {
        _super.prototype.updateWorldMatrix.call(this);
        this.worldMatrixInverse.setInverseOf(this._worldMatrix);
    };
    return Camera;
}(Object3D));

/**
 *
 */
var PerspectiveCamera = /** @class */ (function (_super) {
    __extends(PerspectiveCamera, _super);
    /**
     *
     * @param fov 张角
     * @param aspect 长宽比例width/height
     * @param near 最近近距离
     * @param far 最远远距离
     */
    function PerspectiveCamera(fov, aspect, near, far) {
        if (fov === void 0) { fov = 50; }
        if (aspect === void 0) { aspect = 1; }
        if (near === void 0) { near = 0.1; }
        if (far === void 0) { far = 2000; }
        var _this = _super.call(this) || this;
        _this.fov = fov;
        _this.aspect = aspect;
        _this.near = near;
        _this.far = far;
        _this._instanceType = 'PerspectiveCamera';
        _this.zoom = 1;
        _this.focus = 10;
        _this.updateProjectionMatrix();
        return _this;
    }
    PerspectiveCamera.prototype.set = function (fov, aspect, near, far) {
        if (fov === void 0) { fov = 50; }
        if (aspect === void 0) { aspect = 1; }
        if (near === void 0) { near = 0.1; }
        if (far === void 0) { far = 2000; }
        this.fov = fov;
        this.aspect = aspect;
        this.near = near;
        this.far = far;
        this.zoom = 1;
        this.focus = 10;
        this.updateProjectionMatrix();
    };
    PerspectiveCamera.prototype.copy = function (source, recursive) {
        if (recursive === void 0) { recursive = true; }
        _super.prototype.copy.call(this, source, recursive);
        this.fov = source.fov;
        this.zoom = source.zoom;
        this.near = source.near;
        this.far = source.far;
        this.focus = source.focus;
        this.aspect = source.aspect;
        this.updateProjectionMatrix();
        return this;
    };
    PerspectiveCamera.prototype.clone = function () {
        return new PerspectiveCamera().copy(this);
    };
    /**
     * 更新
     */
    PerspectiveCamera.prototype.updateProjectionMatrix = function () {
        this.projectionMatrix.setPerspective(this.fov, this.aspect, this.near, this.far);
        this.projectionMatrixInverse.setInverseOf(this.projectionMatrix);
    };
    return PerspectiveCamera;
}(Camera));

/**
 * 光源基类，只有颜色和光源强度
 */
var Light = /** @class */ (function (_super) {
    __extends(Light, _super);
    /**
     *
     * @param color rgb三分量的矢量，每个分量0到1，颜色方面后续优化
     * @param intensity 光照强度 0到1 ,直接影响颜色值，不进uniform
     */
    function Light(color, intensity) {
        if (intensity === void 0) { intensity = 1; }
        var _this = _super.call(this) || this;
        _this.intensity = intensity;
        _this._color = 0xffffff;
        _this._colorArr = new Float32Array([1.0, 1.0, 1.0]);
        _this._colorVec3 = new Vector3(1.0, 1.0, 1.0);
        _this.color = color;
        _this._instanceType = "Light";
        return _this;
    }
    Object.defineProperty(Light.prototype, "color", {
        get: function () {
            return this._color;
        },
        set: function (value) {
            if (this._color === value)
                return;
            this._color = value;
            var arr = hex2rgb$1(value);
            this._colorArr[0] = this._colorVec3.x = arr[0];
            this._colorArr[1] = this._colorVec3.y = arr[1];
            this._colorArr[2] = this._colorVec3.z = arr[2];
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Light.prototype, "colorArr", {
        //获取
        get: function () {
            return this._colorArr;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Light.prototype, "colorVec3", {
        get: function () {
            return this._colorVec3;
        },
        enumerable: false,
        configurable: true
    });
    Light.prototype.copy = function (light) {
        _super.prototype.copy.call(this, light);
        this.color = light.color;
        this.intensity = light.intensity;
        this.shadow = light.shadow.clone();
        return this;
    };
    return Light;
}(Object3D));

var Vector2 = /** @class */ (function () {
    function Vector2(x, y) {
        if (x === void 0) { x = 0; }
        if (y === void 0) { y = 0; }
        this.x = x;
        this.y = y;
    }
    Vector2.prototype.set = function (x, y) {
        this.x = x;
        this.y = y;
        return this;
    };
    Vector2.prototype.copy = function (v) {
        this.x = v.x;
        this.y = v.y;
        return this;
    };
    Vector2.prototype.clone = function () {
        return new Vector2(this.x, this.y);
    };
    Vector2.prototype.add = function (v) {
        this.x += v.x;
        this.y += v.y;
        return this;
    };
    Vector2.prototype.addScalar = function (s) {
        this.x += s;
        this.y += s;
        return this;
    };
    Vector2.prototype.addVectors = function (a, b) {
        this.x = a.x + b.x;
        this.y = a.y + b.y;
        return this;
    };
    Vector2.prototype.addScaledVector = function (v, s) {
        this.x += v.x * s;
        this.y += v.y * s;
        return this;
    };
    Vector2.prototype.sub = function (v) {
        this.x -= v.x;
        this.y -= v.y;
        return this;
    };
    Vector2.prototype.subScalar = function (s) {
        this.x -= s;
        this.y -= s;
        return this;
    };
    Vector2.prototype.subVectors = function (a, b) {
        this.x = a.x - b.x;
        this.y = a.y - b.y;
        return this;
    };
    Vector2.prototype.multiply = function (v) {
        this.x *= v.x;
        this.y *= v.y;
        return this;
    };
    Vector2.prototype.multiplyScalar = function (scalar) {
        this.x *= scalar;
        this.y *= scalar;
        return this;
    };
    Vector2.prototype.divide = function (v) {
        this.x /= v.x;
        this.y /= v.y;
        return this;
    };
    Vector2.prototype.divideScalar = function (scalar) {
        return this.multiplyScalar(1 / scalar);
    };
    Vector2.prototype.applyMatrix3 = function (m) {
        var x = this.x, y = this.y;
        var e = m.elements;
        this.x = e[0] * x + e[3] * y + e[6];
        this.y = e[1] * x + e[4] * y + e[7];
        return this;
    };
    Vector2.prototype.dot = function (v) {
        return this.x * v.x + this.y * v.y;
    };
    Vector2.prototype.cross = function (v) {
        return this.x * v.y - this.y * v.x;
    };
    Vector2.prototype.lengthSq = function () {
        return this.x * this.x + this.y * this.y;
    };
    Vector2.prototype.length = function () {
        return Math.sqrt(this.x * this.x + this.y * this.y);
    };
    Vector2.prototype.manhattanLength = function () {
        return Math.abs(this.x) + Math.abs(this.y);
    };
    Vector2.prototype.normalize = function () {
        return this.divideScalar(this.length() || 1);
    };
    Vector2.prototype.angle = function () {
        // computes the angle in radians with respect to the positive x-axis
        var angle = Math.atan2(this.y, this.x);
        if (angle < 0)
            angle += 2 * Math.PI;
        return angle;
    };
    Vector2.prototype.distanceTo = function (v) {
        return Math.sqrt(this.distanceToSquared(v));
    };
    Vector2.prototype.distanceToSquared = function (v) {
        var dx = this.x - v.x, dy = this.y - v.y;
        return dx * dx + dy * dy;
    };
    Vector2.prototype.manhattanDistanceTo = function (v) {
        return Math.abs(this.x - v.x) + Math.abs(this.y - v.y);
    };
    Vector2.prototype.setLength = function (length) {
        return this.normalize().multiplyScalar(length);
    };
    Vector2.prototype.lerp = function (v, alpha) {
        this.x += (v.x - this.x) * alpha;
        this.y += (v.y - this.y) * alpha;
        return this;
    };
    Vector2.prototype.lerpVectors = function (v1, v2, alpha) {
        return this.subVectors(v2, v1).multiplyScalar(alpha).add(v1);
    };
    Vector2.prototype.equals = function (v) {
        return ((v.x === this.x) && (v.y === this.y));
    };
    Vector2.prototype.fromArray = function (array, offset) {
        if (offset === undefined)
            offset = 0;
        this.x = array[offset];
        this.y = array[offset + 1];
        return this;
    };
    Vector2.prototype.toArray = function (array, offset) {
        if (array === void 0) { array = []; }
        if (offset === void 0) { offset = 0; }
        array[offset] = this.x;
        array[offset + 1] = this.y;
        return array;
    };
    return Vector2;
}());

//射线检测工具
var Raycaster = /** @class */ (function (_super) {
    __extends(Raycaster, _super);
    function Raycaster(origin, direction, near, far) {
        if (near === void 0) { near = 0; }
        if (far === void 0) { far = Infinity; }
        var _this = _super.call(this) || this;
        _this.near = near;
        _this.far = far;
        _this._instanceType = "Raycaster";
        _this.ray = new Ray(origin, direction);
        return _this;
    }
    Raycaster.prototype.set = function (origin, direction) {
        this.ray.set(origin, direction);
    };
    Raycaster.prototype.copy = function (raycaster) {
        this.ray.copy(raycaster.ray);
        // near and far?TODO
        return this;
    };
    Raycaster.prototype.clone = function () {
        return new Raycaster().copy(this);
    };
    Raycaster.prototype.setFromCamera = function (coords, camera) {
        // if ( ( camera && camera.isPerspectiveCamera ) ) {
        this.ray.origin.setFromMatrixPosition(camera._worldMatrix);
        this.ray.direction.set(coords.x, coords.y, 0.5).unproject(camera).sub(this.ray.origin).normalize();
        // } else if ( ( camera && camera.isOrthographicCamera ) ) {
        // 	this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera
        // 	this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );
        // } else {
        // 	console.error( 'THREE.Raycaster: Unsupported camera type.' );
        // }
    };
    Raycaster.prototype.intersectObject = function (object, optionalTarget) {
        var intersects = optionalTarget || [];
        intersectObject(object, this, intersects);
        intersects.sort(ascSort);
        return intersects;
    };
    Raycaster.prototype.destroy = function () {
        //TODO
    };
    return Raycaster;
}(HashObject));
function ascSort(a, b) {
    return a.distance - b.distance;
}
function intersectObject(object, raycaster, intersects) {
    if (object.visible === false)
        return;
    if (object.mouseEnable)
        object.raycast(raycaster, intersects);
    if (object.mouseChildren) {
        var children = object.children;
        for (var i = 0, l = children.length; i < l; i++) {
            intersectObject(children[i], raycaster, intersects);
        }
    }
}

var ShadowType;
(function (ShadowType) {
    ShadowType["basic"] = "SHADOWMAP_TYPE_BASIC";
    ShadowType["pcf"] = "SHADOWMAP_TYPE_PCF";
})(ShadowType || (ShadowType = {}));
/**
 * 作为3D的顶级容器，不能被object3D添加，自身不能添加其他2D元素
 * 带透明度的融合有问题，尽量自行调整渲染顺序
 */
var Scene3D = /** @class */ (function (_super) {
    __extends(Scene3D, _super);
    function Scene3D() {
        var _this = _super.call(this) || this;
        _this._viewId = -1;
        _this._viewX = 0;
        _this._viewY = 0;
        _this._viewWidth = 750;
        _this._viewHeight = 1624;
        _this.visible = true;
        _this.raycaster = new Raycaster();
        /**
         * 阴影类型
         */
        _this.shadowType = ShadowType.basic;
        _this._instanceType = "Scene3D";
        _this.scene = _this;
        //@ts-ignore为了添加进容器时候的操作，做个兼容
        _this.transform = { _parentId: 0 };
        _this.camera = new PerspectiveCamera();
        return _this;
    }
    Object.defineProperty(Scene3D.prototype, "viewX", {
        get: function () {
            return this._viewX;
        },
        set: function (value) {
            value = value || 0;
            if (this._viewX === value)
                return;
            this._viewX = value;
            this._viewId = -1;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Scene3D.prototype, "viewY", {
        get: function () {
            return this._viewY;
        },
        set: function (value) {
            value = value || 0;
            if (this._viewY === value)
                return;
            this._viewY = value;
            this._viewId = -1;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Scene3D.prototype, "viewWidth", {
        get: function () {
            return this._viewWidth;
        },
        set: function (value) {
            value = value || 0;
            if (this._viewWidth === value)
                return;
            this._viewWidth = value;
            this._viewId = -1;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Scene3D.prototype, "viewHeight", {
        get: function () {
            return this._viewHeight;
        },
        set: function (value) {
            value = value || 0;
            if (this._viewHeight === value)
                return;
            this._viewHeight = value;
            this._viewId = -1;
        },
        enumerable: false,
        configurable: true
    });
    Scene3D.prototype.setViewRect = function (x, y, width, height) {
        this.viewX = x;
        this.viewY = y;
        this.viewWidth = width;
        this.viewHeight = height;
        this._viewId = -1;
    };
    Scene3D.prototype.setFog = function (color, near, far /*density: number = 0.00025*/) {
        if (color === void 0) { color = 0xffffff; }
        if (near === void 0) { near = 0; }
        if (far === void 0) { far = 100; }
        var arr = hex2rgb$1(color);
        if (this._fog) {
            this._fog.color[0] = arr[0];
            this._fog.color[1] = arr[1];
            this._fog.color[2] = arr[2];
            // this._fog.density = density
            this._fog.near = near;
            this._fog.far = far;
        }
        else {
            this._fog = { color: new Float32Array(arr), near: near, far: far /*density*/ };
        }
    };
    Scene3D.prototype.removeFog = function () {
        this._fog = null;
    };
    Object.defineProperty(Scene3D.prototype, "filters", {
        get: function () { return this._filters && this._filters.slice(); },
        set: function (value) { this._filters = value && value.slice(); },
        enumerable: false,
        configurable: true
    });
    //只处理自己的xy坐标
    Scene3D.prototype.updateTransform = function () {
        if (!this.visible)
            return;
        //子级统统自己的更新方法
        this.updateWorldMatrix();
    };
    Scene3D.prototype.renderWebGL = function (renderer) {
        if (!this.visible)
            return;
        //切换渲染插件
        var plugin = renderer.plugins["d3"];
        //传入camera数据，着色器各自传
        this.camera.updateWorldMatrix();
        plugin.camera = this.camera;
        //处理所有灯，只找同一级的？还是递归找灯
        plugin.lightsConfig = this.getLightConfig();
        //雾化
        plugin.fog = this._fog || null;
        //阴影类型
        plugin.shadowType = this.shadowType;
        //设置插件，会调用start，如果是两个场景，会有问题，因为是同一个插件不会flush上一个，到时注意修改
        renderer.batchManager.setObjectRenderer(plugin);
        this.setViewport(renderer);
        plugin.viewport = this._viewport;
        //处理子级东西
        if (this.filters && this.filters.length) {
            //估计没必要
            // renderer.batchManager.flush();
            var filters = this.filters;
            if (filters) {
                if (!this._enabledFilters)
                    this._enabledFilters = [];
                //重置
                this._enabledFilters.length = 0;
                //筛选可用的
                for (var i = 0; i < filters.length; i++) {
                    if (filters[i].enabled)
                        this._enabledFilters.push(filters[i]);
                }
                //@ts-ignore
                if (this._enabledFilters.length)
                    renderer.filterManager.pushFilter(this, this._enabledFilters);
            }
            this.render(renderer);
            //刷掉批处理
            renderer.batchManager.flush();
            //移除滤镜
            if (filters && this._enabledFilters && this._enabledFilters.length)
                renderer.filterManager.popFilter();
        }
        else {
            this.render(renderer);
        }
    };
    Scene3D.prototype.setViewport = function (renderer) {
        if (this._viewId !== this.parent.transform._worldID) {
            this._viewId = this.parent.transform._worldID;
            var pt = this.parent.transform.worldMatrix;
            var x = (this.viewX * pt.a) + (this.viewY * pt.c) + pt.tx;
            var y = (this.viewX * pt.b) + (this.viewY * pt.d) + pt.ty;
            //计算实际的viewWidth和viewHeight，简单点直接是父级的缩放，还是要全局的缩放，如果只在舞台
            var scaleX = Math.sqrt((pt.a * pt.a) + (pt.b * pt.b));
            var scaleY = Math.sqrt((pt.c * pt.c) + (pt.d * pt.d));
            //记录
            this._viewport = {
                x: x,
                y: renderer.height - y - this.viewHeight * scaleY,
                width: this.viewWidth * scaleX,
                height: this.viewHeight * scaleY
            };
        }
        this._viewport && renderer.gl.viewport(this._viewport.x, this._viewport.y, this._viewport.width, this._viewport.height);
    };
    Scene3D.prototype.getBounds = function () {
        var pt = this.parent.transform.worldMatrix;
        var y = (this.viewX * pt.b) + (this.viewY * pt.d) + pt.ty;
        return new Rectangle(this._viewport.x, y, this._viewport.width, this._viewport.height);
    };
    Scene3D.prototype.getLightConfig = function (con, arr) {
        if (con === void 0) { con = this; }
        if (arr === void 0) { arr = { pointLights: [], directionalLights: [], ambientLightColor: [0, 0, 0] }; }
        var viewMatrix = this.camera.worldMatrixInverse;
        for (var i = 0; i < con.children.length; i++) {
            var c = con.children[i];
            if (c instanceof Light) {
                var color = c.colorVec3.clone().multiplyScalar(c.intensity).toArray();
                if (c.instanceType == "AmbientLight") {
                    arr.ambientLightColor[0] += color[0];
                    arr.ambientLightColor[1] += color[1];
                    arr.ambientLightColor[2] += color[2];
                }
                else if (c.instanceType == "PointLight") {
                    var position = new Vector3().setFromMatrixPosition(c._worldMatrix);
                    position.applyMatrix4(viewMatrix); //这步是否需要，待测试
                    arr.pointLights.push({
                        color: color,
                        position: position.toArray(),
                        distance: c["distance"],
                        decay: c["distance"] === 0 ? 0.0 : c["decay"],
                    });
                }
                else if (c.instanceType == "DirectionalLight") {
                    var direction = new Vector3().setFromMatrixPosition(c._worldMatrix);
                    direction.sub(new Vector3().setFromMatrixPosition(c["target"]._worldMatrix));
                    direction.transformDirection(viewMatrix);
                    var shadowMatrixDepth;
                    if (c.castShadow) { //这里直接计算了灯光的相机吧
                        if (!c.shadow.map) ;
                        var shadowCamera = c.shadow.camera, shadowMatrix = c.shadow.matrix, lightP = c._worldMatrix.elements.slice(12, 15), lightTargetP = c["target"]._worldMatrix.elements.slice(12, 15);
                        shadowCamera.position.set(lightP[0], lightP[1], lightP[2]);
                        shadowCamera.lookAt(lightTargetP[0], lightTargetP[1], lightTargetP[2]);
                        shadowCamera.updateWorldMatrix();
                        //利用shadowMatrix算一次
                        shadowMatrixDepth = shadowMatrix.setIdentity()
                            .multiply(shadowCamera.projectionMatrix)
                            .multiply(shadowCamera.worldMatrixInverse).toArray();
                        //重算几次
                        shadowMatrix.set(//这里为了减少着色器里的计算
                        0.5, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 1.0);
                        shadowMatrix.multiply(shadowCamera.projectionMatrix);
                        shadowMatrix.multiply(shadowCamera.worldMatrixInverse);
                    }
                    arr.directionalLights.push({
                        color: color,
                        direction: direction.normalize().toArray(),
                        castShadow: c.castShadow,
                        shadowMatrixDepth: shadowMatrixDepth,
                        shadowMatrix: c.shadow.matrix.toArray(),
                        bias: c.shadow.bias,
                        radius: c.shadow.radius,
                        mapSize: [c.shadow.mapSize.x, c.shadow.mapSize.y]
                    });
                }
            }
            if (c.children && c.children.length)
                this.getLightConfig(c, arr);
        }
        return arr;
    };
    /**
     * 点击事件，只算场景的先，待mesh等写完所有2d包围盒再说，将几何转成2d的点后，根据索引的所有三角面计算是否选中
     * @param globalPoint
     * @param isMouseEvent
     */
    Scene3D.prototype.hitTestPoint = function (globalPoint, isMouseEvent) {
        if (!this.parent || !this.mouseEnable)
            return null;
        //转成全局
        var pt = this.parent.transform.worldMatrix;
        var x = (this.viewX * pt.a) + (this.viewY * pt.c) + pt.tx;
        var y = (this.viewX * pt.b) + (this.viewY * pt.d) + pt.ty;
        //计算实际的viewWidth和viewHeight，简单点直接是父级的缩放，还是要全局的缩放，如果只在舞台
        var scaleX = Math.sqrt((pt.a * pt.a) + (pt.b * pt.b));
        var scaleY = Math.sqrt((pt.c * pt.c) + (pt.d * pt.d));
        var w = this.viewWidth * scaleX;
        var h = this.viewHeight * scaleY;
        if (globalPoint.x >= x && globalPoint.x <= (x + w) && globalPoint.y >= y && globalPoint.y <= (y + h)) ;
        else {
            return null;
        }
        //检查场景中的
        if (this.mouseChildren) {
            //canvas上的坐标，转成视窗内的坐标，暂时不管旋转的，也不允许scene3D视窗旋转
            x = ((globalPoint.x - x) / w) * 2 - 1;
            y = -((globalPoint.y - y) / h) * 2 + 1;
            this.raycaster.setFromCamera(new Vector3(x, y, 0.5), this.camera);
            //只需要距离最近的那个就行
            var arr = this.raycaster.intersectObject(this);
            if (arr.length)
                return arr[0].object;
        }
        return this;
    };
    Scene3D.prototype.setOrbCtrCfg = function (options) {
        var cfg = this.orbitControlConfig;
        if (!cfg || !options)
            return;
        for (var key in options) {
            if (cfg[key] !== undefined)
                cfg[key] = options[key];
        }
    };
    //相机控件
    Scene3D.prototype.setOrbitControl = function (options) {
        var _this = this;
        if (this.orbitControlConfig)
            return;
        this.orbitControlConfig = {
            enabled: true,
            enableDamping: true,
            dampingFactor: 0.25,
            userZoom: true,
            userZoomSpeed: 1.0,
            userRotate: true,
            userRotateSpeed: 1.0,
            autoRotate: false,
            autoRotateSpeed: 2.0,
            //最小旋转角
            minPolarAngle: 0,
            //最大旋转角
            maxPolarAngle: Math.PI,
            minDistance: 0,
            maxDistance: Infinity,
            enablePitch: true
        };
        //设置属性
        this.setOrbCtrCfg(options);
        var cfg = this.orbitControlConfig;
        // pitch，yaw，roll;为俯仰角，偏航角，翻滚角
        // panOffset.multiplyScalar( 1 - scope.dampingFactor );
        //相机目标点
        var center = new Vector3();
        // this.userPan = true;
        // this.userPanSpeed = 2.0;
        var EPS = 0.000001;
        var PIXELS_PER_ROUND = 1800;
        var rotateStart = new Vector2();
        var rotateEnd = new Vector2();
        var rotateDelta = new Vector2();
        var phiDelta = 0;
        var thetaDelta = 0;
        var scale = 1;
        function getAutoRotationAngle() {
            return 2 * Math.PI / 60 / 60 * cfg.autoRotateSpeed;
        }
        function getZoomScale() {
            return Math.pow(0.95, cfg.userZoomSpeed);
        }
        function rotateLeft(angle) {
            if (angle === void 0) { angle = getAutoRotationAngle(); }
            thetaDelta -= angle;
        }
        function rotateUp(angle) {
            if (angle === void 0) { angle = getAutoRotationAngle(); }
            phiDelta -= angle;
        }
        function zoomIn(zoomScale) {
            if (zoomScale === void 0) { zoomScale = getZoomScale(); }
            scale /= zoomScale;
        }
        function zoomOut(zoomScale) {
            if (zoomScale === void 0) { zoomScale = getZoomScale(); }
            scale *= zoomScale;
        }
        var update = function () {
            if (Math.abs(thetaDelta) < 0.0001 &&
                Math.abs(phiDelta) < 0.0001 &&
                Math.abs(scale - 1) < 0.0001 &&
                !cfg.autoRotate) {
                return;
            }
            var position = _this.camera.position;
            var offset = position.clone().sub(center);
            var theta = Math.atan2(offset.x, offset.z);
            var phi = Math.atan2(Math.sqrt(offset.x * offset.x + offset.z * offset.z), offset.y);
            if (cfg.autoRotate)
                rotateLeft();
            theta += thetaDelta;
            phi += phiDelta;
            phi = Math.max(cfg.minPolarAngle, Math.min(cfg.maxPolarAngle, phi));
            phi = Math.max(EPS, Math.min(Math.PI - EPS, phi));
            var radius = offset.length() * scale;
            // restrict radius to be between desired limits
            radius = Math.max(cfg.minDistance, Math.min(cfg.maxDistance, radius));
            offset.x = radius * Math.sin(phi) * Math.sin(theta);
            offset.y = radius * Math.cos(phi);
            offset.z = radius * Math.sin(phi) * Math.cos(theta);
            //相机位置
            position.copy(center).add(offset);
            //相机目标点
            _this.camera.lookAt(center.x, center.y, center.z);
            //恢复
            if (cfg.enableDamping) {
                thetaDelta *= (1 - cfg.dampingFactor);
                phiDelta *= (1 - cfg.dampingFactor);
            }
            else {
                thetaDelta = 0;
                phiDelta = 0;
            }
            scale = 1;
            // if (lastPosition.distanceTo(this.object.position) > 0) {
            //     this.dispatchEvent(changeEvent);
            //     lastPosition.copy(this.object.position);
            // }
        };
        //记录两个手指唯一标识
        var fingles = [];
        var deltaDis = 0;
        //事件，暂时只有旋转，其他判断先不要了
        this.addEventListener(MouseEvent.MOUSE_DOWN, function (e) {
            if (!cfg.enabled)
                return;
            fingles.push({ x: e.clientX, y: e.clientY, id: e.identifier });
            if (fingles.length >= 2) {
                var f1 = fingles[fingles.length - 1];
                var f2 = fingles[fingles.length - 2];
                deltaDis = Math.sqrt(Math.pow(f1.x - f2.x, 2) + Math.pow(f1.y - f2.y, 2));
            }
            // e.stopPropagation();
            rotateStart.set(e.clientX, e.clientY);
        }, this);
        this.addEventListener(MouseEvent.MOUSE_MOVE, function (e) {
            if (!cfg.enabled)
                return;
            if (!fingles.length)
                return;
            if (fingles.length == 1) {
                if (!cfg.userRotate)
                    return;
                if (!rotateStart.x && !rotateStart.y)
                    return;
                rotateEnd.set(e.clientX, e.clientY);
                rotateDelta.subVectors(rotateEnd, rotateStart);
                rotateLeft(2 * Math.PI * rotateDelta.x / PIXELS_PER_ROUND * cfg.userRotateSpeed);
                if (cfg.enablePitch)
                    rotateUp(2 * Math.PI * rotateDelta.y / PIXELS_PER_ROUND * cfg.userRotateSpeed);
                rotateStart.copy(rotateEnd);
                //更新
                // update();
            }
            //多指，取最后两个，如果两个都移动，怎么保证就一个刷新
            else {
                if (cfg.userZoom === false)
                    return;
                var oneF = fingles[fingles.length - 1];
                var twoF = fingles[fingles.length - 2];
                if (e.identifier == oneF.id) {
                    oneF.x = e.clientX;
                    oneF.y = e.clientY;
                }
                else if (e.identifier == twoF.id) {
                    twoF.x = e.clientX;
                    twoF.y = e.clientY;
                }
                else {
                    return;
                }
                var cDelta = Math.sqrt(Math.pow(oneF.x - twoF.x, 2) + Math.pow(oneF.y - twoF.y, 2));
                if (cDelta - deltaDis > 0) {
                    zoomOut(Math.pow(0.95, cfg.userZoomSpeed / 3)); //手势的执行太快了
                }
                else {
                    zoomIn(Math.pow(0.95, cfg.userZoomSpeed / 3));
                }
                //更新
                // update();
                deltaDis = cDelta;
            }
        }, this);
        var up = function (e) {
            fingles.length = 0;
            // for (var i = 0; i < fingles.length; i++) {
            //     if (fingles[i].id == e.identifier) {
            //         fingles.splice(i, 1);
            //         rotateStart.set(0, 0);
            //         return;
            //     }
            // }
        };
        this.addEventListener(MouseEvent.MOUSE_UP, up, this);
        this.addEventListener(MouseEvent.MOUSE_OUT, up, this);
        //加个自动旋转的
        this.addEventListener(MouseEvent.ENTER_FRAME, function () {
            /*if (autoRotate)*/ update();
        }, this);
        //监听下滚轮
        if (document)
            document.addEventListener('mousewheel', function (event) {
                if (!cfg.enabled || !cfg.userZoom)
                    return;
                var delta = 0;
                // event.preventDefault();
                if (event["wheelDelta"]) { // WebKit / Opera / Explorer 9
                    delta = event["wheelDelta"];
                }
                else if (event["detail"]) { // Firefox
                    delta = -event["detail"];
                }
                if (delta > 0) {
                    zoomOut();
                }
                else {
                    zoomIn();
                }
                // update();
            }, false);
    };
    return Scene3D;
}(Object3D));
// window['$'].ajax({
//     type: "get",
//     url: "//embedlog.duiba.com.cn/exposure/standard",
//     dataType: "jsonp",
//     data: {
//         dpm: 72915 + '.' + 110 + '.' + 1 + '.' + 1,
//         dcm: 202 + '.' + 1 + '.' + 0 + '.' + 0,
//         appId: 72915,
//         domain: '//embedlog.duiba.com.cn'
//     },
//     async: true,
//     success: (result) => {
//     },
//     error: (message) => {
//     }
// });

/**
 * 球形几何
 * 直接参考three的计算方式
 */
var SphereGeometry = /** @class */ (function (_super) {
    __extends(SphereGeometry, _super);
    function SphereGeometry(radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength) {
        if (radius === void 0) { radius = 1; }
        if (widthSegments === void 0) { widthSegments = 8; }
        if (heightSegments === void 0) { heightSegments = 6; }
        if (phiStart === void 0) { phiStart = 0; }
        if (phiLength === void 0) { phiLength = Math.PI * 2; }
        if (thetaStart === void 0) { thetaStart = 0; }
        if (thetaLength === void 0) { thetaLength = Math.PI; }
        var _this = this;
        //处理分段，必须正整数
        widthSegments = Math.max(3, Math.floor(widthSegments));
        heightSegments = Math.max(2, Math.floor(heightSegments));
        //计算所有顶点，及索引及法线
        var thetaEnd = thetaStart + thetaLength;
        var ix, iy;
        var index = 0;
        var grid = [];
        var vertex = new Vector3();
        var normal = new Vector3();
        // buffers
        var indices = [];
        var vertices = [];
        var normals = [];
        var uvs = [];
        // generate vertices, normals and uvs
        for (iy = 0; iy <= heightSegments; iy++) {
            var verticesRow = [];
            var v = iy / heightSegments;
            for (ix = 0; ix <= widthSegments; ix++) {
                var u = ix / widthSegments;
                // vertex
                vertex.x = -radius * Math.cos(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength);
                vertex.y = radius * Math.cos(thetaStart + v * thetaLength);
                vertex.z = radius * Math.sin(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength);
                vertices.push(vertex.x, vertex.y, vertex.z);
                // normal
                normal.set(vertex.x, vertex.y, vertex.z).normalize();
                normals.push(normal.x, normal.y, normal.z);
                // uv
                // uvs.push(u, 1 - v);
                uvs.push(u, v); //2d里面颠倒过贴图的y轴（其实是矫正）。所以v统统不用1-
                verticesRow.push(index++);
            }
            grid.push(verticesRow);
        }
        // indices
        for (iy = 0; iy < heightSegments; iy++) {
            for (ix = 0; ix < widthSegments; ix++) {
                var a = grid[iy][ix + 1];
                var b = grid[iy][ix];
                var c = grid[iy + 1][ix];
                var d = grid[iy + 1][ix + 1];
                if (iy !== 0 || thetaStart > 0)
                    indices.push(a, b, d);
                if (iy !== heightSegments - 1 || thetaEnd < Math.PI)
                    indices.push(b, c, d);
            }
        }
        _this = _super.call(this, vertices, indices, normals, null, uvs) || this;
        //直接计算包围球
        _this.boundingSphere = new Sphere(new Vector3(), radius);
        return _this;
    }
    return SphereGeometry;
}(Geometry));

/**
 * 顶点创建方式直接用three的
 * 以后记录长宽高属性，标记是否更新顶点等数据
 */
var BoxGeometry = /** @class */ (function (_super) {
    __extends(BoxGeometry, _super);
    /**
     *
     * @param width x
     * @param height y
     * @param depth z
     * @param widthSegments
     * @param heightSegments
     * @param depthSegments
     */
    function BoxGeometry(width, height, depth, widthSegments, heightSegments, depthSegments) {
        if (width === void 0) { width = 1; }
        if (height === void 0) { height = 1; }
        if (depth === void 0) { depth = 1; }
        if (widthSegments === void 0) { widthSegments = 1; }
        if (heightSegments === void 0) { heightSegments = 1; }
        if (depthSegments === void 0) { depthSegments = 1; }
        var _this = this;
        // segments
        widthSegments = Math.floor(widthSegments) || 1;
        heightSegments = Math.floor(heightSegments) || 1;
        depthSegments = Math.floor(depthSegments) || 1;
        // buffers
        var indices = [];
        var vertices = [];
        var normals = [];
        var uvs = [];
        // helper variables
        var numberOfVertices = 0;
        // build each side of the box geometry
        buildPlane('z', 'y', 'x', -1, -1, depth, height, width, depthSegments, heightSegments); // px
        buildPlane('z', 'y', 'x', 1, -1, depth, height, -width, depthSegments, heightSegments); // nx
        buildPlane('x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments); // py
        buildPlane('x', 'z', 'y', 1, -1, width, depth, -height, widthSegments, depthSegments); // ny
        buildPlane('x', 'y', 'z', 1, -1, width, height, depth, widthSegments, heightSegments); // pz
        buildPlane('x', 'y', 'z', -1, -1, width, height, -depth, widthSegments, heightSegments); // nz
        function buildPlane(u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex) {
            var segmentWidth = width / gridX;
            var segmentHeight = height / gridY;
            var widthHalf = width / 2;
            var heightHalf = height / 2;
            var depthHalf = depth / 2;
            var gridX1 = gridX + 1;
            var gridY1 = gridY + 1;
            var vertexCounter = 0;
            var ix, iy;
            var vector = new Vector3();
            // generate vertices, normals and uvs
            for (iy = 0; iy < gridY1; iy++) {
                var y = iy * segmentHeight - heightHalf;
                for (ix = 0; ix < gridX1; ix++) {
                    var x = ix * segmentWidth - widthHalf;
                    // set values to correct vector component
                    vector[u] = x * udir;
                    vector[v] = y * vdir;
                    vector[w] = depthHalf;
                    // now apply vector to vertex buffer
                    vertices.push(vector.x, vector.y, vector.z);
                    // set values to correct vector component
                    vector[u] = 0;
                    vector[v] = 0;
                    vector[w] = depth > 0 ? 1 : -1;
                    // now apply vector to normal buffer
                    normals.push(vector.x, vector.y, vector.z);
                    // uvs
                    uvs.push(ix / gridX);
                    // uvs.push(1 - (iy / gridY));
                    uvs.push(iy / gridY); //2D里面颠倒过贴图
                    // counters
                    vertexCounter += 1;
                }
            }
            // indices
            // 1. you need three indices to draw a single face
            // 2. a single segment consists of two faces
            // 3. so we need to generate six (2*3) indices per segment
            for (iy = 0; iy < gridY; iy++) {
                for (ix = 0; ix < gridX; ix++) {
                    var a = numberOfVertices + ix + gridX1 * iy;
                    var b = numberOfVertices + ix + gridX1 * (iy + 1);
                    var c = numberOfVertices + (ix + 1) + gridX1 * (iy + 1);
                    var d = numberOfVertices + (ix + 1) + gridX1 * iy;
                    // faces
                    indices.push(a, b, d);
                    indices.push(b, c, d);
                }
            }
            // update total number of vertices
            numberOfVertices += vertexCounter;
        }
        //传入数据
        _this = _super.call(this, vertices, indices, normals, null, uvs) || this;
        //直接计算包围盒
        _this.boundingBox = new Box3(new Vector3(-width / 2, -height / 2, -depth / 2), new Vector3(width / 2, height / 2, depth / 2));
        //直接计算包围球
        _this.boundingSphere = new Sphere(new Vector3(), Math.sqrt(width * width + height * height + depth * depth));
        return _this;
    }
    return BoxGeometry;
}(Geometry));

var PlaneGeometry = /** @class */ (function (_super) {
    __extends(PlaneGeometry, _super);
    function PlaneGeometry(width, height, widthSegments, heightSegments) {
        if (width === void 0) { width = 1; }
        if (height === void 0) { height = 1; }
        if (widthSegments === void 0) { widthSegments = 1; }
        if (heightSegments === void 0) { heightSegments = 1; }
        var _this = this;
        var width_half = width / 2;
        var height_half = height / 2;
        var gridX = Math.floor(widthSegments);
        var gridY = Math.floor(heightSegments);
        var gridX1 = gridX + 1;
        var gridY1 = gridY + 1;
        var segment_width = width / gridX;
        var segment_height = height / gridY;
        var ix, iy;
        // buffers
        var indices = [];
        var vertices = [];
        var normals = [];
        var uvs = [];
        // generate vertices, normals and uvs
        for (iy = 0; iy < gridY1; iy++) {
            var y = iy * segment_height - height_half;
            for (ix = 0; ix < gridX1; ix++) {
                var x = ix * segment_width - width_half;
                vertices.push(x, -y, 0);
                normals.push(0, 0, 1);
                uvs.push(ix / gridX);
                // uvs.push(1 - (iy / gridY));
                uvs.push(iy / gridY);
            }
        }
        // indices
        for (iy = 0; iy < gridY; iy++) {
            for (ix = 0; ix < gridX; ix++) {
                var a = ix + gridX1 * iy;
                var b = ix + gridX1 * (iy + 1);
                var c = (ix + 1) + gridX1 * (iy + 1);
                var d = (ix + 1) + gridX1 * iy;
                // faces
                indices.push(a, b, d);
                indices.push(b, c, d);
            }
        }
        _this = _super.call(this, vertices, indices, normals, null, uvs) || this;
        return _this;
    }
    return PlaneGeometry;
}(Geometry));

var CircleGeometry = /** @class */ (function (_super) {
    __extends(CircleGeometry, _super);
    function CircleGeometry(radius, segments, thetaStart, thetaLength) {
        if (radius === void 0) { radius = 1; }
        if (segments === void 0) { segments = 8; }
        if (thetaStart === void 0) { thetaStart = 0; }
        if (thetaLength === void 0) { thetaLength = Math.PI * 2; }
        var _this = this;
        segments = Math.max(3, segments);
        var indices = [];
        var vertices = [];
        var normals = [];
        var uvs = [];
        var i, s;
        var vertex = new Vector3();
        var uv = new Vector2();
        // center point
        vertices.push(0, 0, 0);
        normals.push(0, 0, 1);
        uvs.push(0.5, 0.5);
        for (s = 0, i = 3; s <= segments; s++, i += 3) {
            var segment = thetaStart + s / segments * thetaLength;
            // vertex
            vertex.x = radius * Math.cos(segment);
            vertex.y = radius * Math.sin(segment);
            vertices.push(vertex.x, vertex.y, vertex.z);
            // normal
            normals.push(0, 0, 1);
            // uvs
            uv.x = (vertices[i] / radius + 1) / 2;
            // uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2;
            uv.y = 1 - (vertices[i + 1] / radius + 1) / 2;
            uvs.push(uv.x, uv.y);
        }
        // indices
        for (i = 1; i <= segments; i++) {
            indices.push(i, i + 1, 0);
        }
        _this = _super.call(this, vertices, indices, normals, null, uvs) || this;
        return _this;
    }
    return CircleGeometry;
}(Geometry));

var CylinderGeometry = /** @class */ (function (_super) {
    __extends(CylinderGeometry, _super);
    function CylinderGeometry(
    /**
     * 上圆半径，默认1
     */
    radiusTop, 
    /**
     * 下圆半径，默认1
     */
    radiusBottom, 
    /**
     * 高度，默认1
     */
    height, 
    /**
     * 径向分段数，整数，默认8
     */
    radialSegments, 
    /**
     * 高度分段数，整数，默认1
     */
    heightSegments, 
    /**
     * 是否开口，默认false
     */
    openEnded, 
    /**
     * 圆柱开始角度，默认0
     */
    thetaStart, 
    /**
     * 圆柱结束角度，默认Math.PI * 2
     */
    thetaLength) {
        if (radiusTop === void 0) { radiusTop = 1; }
        if (radiusBottom === void 0) { radiusBottom = 1; }
        if (height === void 0) { height = 1; }
        if (radialSegments === void 0) { radialSegments = 8; }
        if (heightSegments === void 0) { heightSegments = 1; }
        if (openEnded === void 0) { openEnded = false; }
        if (thetaStart === void 0) { thetaStart = 0; }
        if (thetaLength === void 0) { thetaLength = Math.PI * 2; }
        var _this = this;
        //避免小数和0
        radialSegments = Math.floor(radialSegments) || 8;
        heightSegments = Math.floor(heightSegments) || 1;
        var indices = [];
        var vertices = [];
        var normals = [];
        var uvs = [];
        var index = 0;
        var indexArray = [];
        var halfHeight = height / 2;
        // generate geometry
        generateTorso();
        if (!openEnded) {
            if (radiusTop > 0)
                generateCap(true);
            if (radiusBottom > 0)
                generateCap(false);
        }
        // build geometry
        // this.setIndex(indices);
        // this.addAttribute('position', new Float32BufferAttribute(vertices, 3));
        // this.addAttribute('normal', new Float32BufferAttribute(normals, 3));
        // this.addAttribute('uv', new Float32BufferAttribute(uvs, 2));
        function generateTorso() {
            var x, y;
            var normal = new Vector3();
            var vertex = new Vector3();
            // this will be used to calculate the normal
            var slope = (radiusBottom - radiusTop) / height;
            // generate vertices, normals and uvs
            for (y = 0; y <= heightSegments; y++) {
                var indexRow = [];
                var v = y / heightSegments;
                // calculate the radius of the current row
                var radius = v * (radiusBottom - radiusTop) + radiusTop;
                for (x = 0; x <= radialSegments; x++) {
                    var u = x / radialSegments;
                    var theta = u * thetaLength + thetaStart;
                    var sinTheta = Math.sin(theta);
                    var cosTheta = Math.cos(theta);
                    // vertex
                    vertex.x = radius * sinTheta;
                    vertex.y = -v * height + halfHeight;
                    vertex.z = radius * cosTheta;
                    vertices.push(vertex.x, vertex.y, vertex.z);
                    // normal
                    normal.set(sinTheta, slope, cosTheta).normalize();
                    normals.push(normal.x, normal.y, normal.z);
                    // uv
                    // uvs.push(u, 1 - v);
                    uvs.push(u, v);
                    // save index of vertex in respective row
                    indexRow.push(index++);
                }
                // now save vertices of the row in our index array
                indexArray.push(indexRow);
            }
            // generate indices
            for (x = 0; x < radialSegments; x++) {
                for (y = 0; y < heightSegments; y++) {
                    // we use the index array to access the correct indices
                    var a = indexArray[y][x];
                    var b = indexArray[y + 1][x];
                    var c = indexArray[y + 1][x + 1];
                    var d = indexArray[y][x + 1];
                    // faces
                    indices.push(a, b, d);
                    indices.push(b, c, d);
                }
            }
        }
        function generateCap(top) {
            var x, centerIndexStart, centerIndexEnd;
            var uv = new Vector2();
            var vertex = new Vector3();
            var radius = (top === true) ? radiusTop : radiusBottom;
            var sign = (top === true) ? 1 : -1;
            // save the index of the first center vertex
            centerIndexStart = index;
            // first we generate the center vertex data of the cap.
            // because the geometry needs one set of uvs per face,
            // we must generate a center vertex per face/segment
            for (x = 1; x <= radialSegments; x++) {
                // vertex
                vertices.push(0, halfHeight * sign, 0);
                // normal
                normals.push(0, sign, 0);
                // uv
                uvs.push(0.5, 0.5);
                // increase index
                index++;
            }
            // save the index of the last center vertex
            centerIndexEnd = index;
            // now we generate the surrounding vertices, normals and uvs
            for (x = 0; x <= radialSegments; x++) {
                var u = x / radialSegments;
                var theta = u * thetaLength + thetaStart;
                var cosTheta = Math.cos(theta);
                var sinTheta = Math.sin(theta);
                // vertex
                vertex.x = radius * sinTheta;
                vertex.y = halfHeight * sign;
                vertex.z = radius * cosTheta;
                vertices.push(vertex.x, vertex.y, vertex.z);
                // normal
                normals.push(0, sign, 0);
                // uv
                uv.x = (cosTheta * 0.5) + 0.5;
                uv.y = (sinTheta * 0.5 * sign) + 0.5;
                uvs.push(uv.x, uv.y);
                // increase index
                index++;
            }
            // generate indices
            for (x = 0; x < radialSegments; x++) {
                var c = centerIndexStart + x;
                var i = centerIndexEnd + x;
                if (top === true) {
                    // face top
                    indices.push(i, i + 1, c);
                }
                else {
                    // face bottom
                    indices.push(i + 1, i, c);
                }
            }
        }
        _this = _super.call(this, vertices, indices, normals, null, uvs) || this;
        return _this;
    }
    return CylinderGeometry;
}(Geometry));

/*
 * RingGeometry.ts
 * Created by 还有醋v on 2021/4/15.
 * Copyright © 2021 haiyoucuv. All rights reserved.
 */
var RingGeometry = /** @class */ (function (_super) {
    __extends(RingGeometry, _super);
    function RingGeometry(innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength) {
        if (innerRadius === void 0) { innerRadius = 0.5; }
        if (outerRadius === void 0) { outerRadius = 1; }
        if (thetaSegments === void 0) { thetaSegments = 8; }
        if (phiSegments === void 0) { phiSegments = 1; }
        if (thetaStart === void 0) { thetaStart = 0; }
        if (thetaLength === void 0) { thetaLength = Math.PI * 2; }
        var _this = this;
        thetaSegments = Math.max(3, thetaSegments);
        phiSegments = Math.max(1, phiSegments);
        // buffers
        var indices = [];
        var vertices = [];
        var normals = [];
        var uvs = [];
        // some helper variables
        var segment;
        var radius = innerRadius;
        var radiusStep = ((outerRadius - innerRadius) / phiSegments);
        var vertex = new Vector3();
        var uv = new Vector2();
        var j, i;
        // generate vertices, normals and uvs
        for (j = 0; j <= phiSegments; j++) {
            for (i = 0; i <= thetaSegments; i++) {
                // values are generate from the inside of the ring to the outside
                segment = thetaStart + i / thetaSegments * thetaLength;
                // vertex
                vertex.x = radius * Math.cos(segment);
                vertex.y = radius * Math.sin(segment);
                vertices.push(vertex.x, vertex.y, vertex.z);
                // normal
                normals.push(0, 0, 1);
                // uv
                uv.x = (vertex.x / outerRadius + 1) / 2;
                uv.y = 1 - (vertex.y / outerRadius + 1) / 2;
                uvs.push(uv.x, uv.y);
            }
            // increase the radius for next row of vertices
            radius += radiusStep;
        }
        // indices
        for (j = 0; j < phiSegments; j++) {
            var thetaSegmentLevel = j * (thetaSegments + 1);
            for (i = 0; i < thetaSegments; i++) {
                segment = i + thetaSegmentLevel;
                var a = segment;
                var b = segment + thetaSegments + 1;
                var c = segment + thetaSegments + 2;
                var d = segment + 1;
                // faces
                indices.push(a, b, d);
                indices.push(b, c, d);
            }
        }
        _this = _super.call(this, vertices, indices, normals, null, uvs) || this;
        return _this;
    }
    return RingGeometry;
}(Geometry));

/**
 * @author oosmoxiecode
 * @author mrdoob / http://mrdoob.com/
 * @author Mugen87 / https://github.com/Mugen87
 */
var TorusGeometry = /** @class */ (function (_super) {
    __extends(TorusGeometry, _super);
    function TorusGeometry(radius, tube, radialSegments, tubularSegments, arc) {
        if (radius === void 0) { radius = 1; }
        if (tube === void 0) { tube = 0.4; }
        if (radialSegments === void 0) { radialSegments = 8; }
        if (tubularSegments === void 0) { tubularSegments = 6; }
        if (arc === void 0) { arc = Math.PI * 2; }
        var _this = this;
        radialSegments = Math.floor(radialSegments);
        tubularSegments = Math.floor(tubularSegments);
        // buffers
        var indices = [];
        var vertices = [];
        var normals = [];
        var uvs = [];
        // helper variables
        var center = new Vector3();
        var vertex = new Vector3();
        var normal = new Vector3();
        var j, i;
        // generate vertices, normals and uvs
        for (j = 0; j <= radialSegments; j++) {
            for (i = 0; i <= tubularSegments; i++) {
                var u = i / tubularSegments * arc;
                var v = j / radialSegments * Math.PI * 2;
                // vertex
                vertex.x = (radius + tube * Math.cos(v)) * Math.cos(u);
                vertex.y = (radius + tube * Math.cos(v)) * Math.sin(u);
                vertex.z = tube * Math.sin(v);
                vertices.push(vertex.x, vertex.y, vertex.z);
                // normal
                center.x = radius * Math.cos(u);
                center.y = radius * Math.sin(u);
                normal.subVectors(vertex, center).normalize();
                normals.push(normal.x, normal.y, normal.z);
                // uv
                uvs.push(i / tubularSegments);
                uvs.push(1 - j / radialSegments);
            }
        }
        // generate indices
        for (j = 1; j <= radialSegments; j++) {
            for (i = 1; i <= tubularSegments; i++) {
                // indices
                var a = (tubularSegments + 1) * j + i - 1;
                var b = (tubularSegments + 1) * (j - 1) + i - 1;
                var c = (tubularSegments + 1) * (j - 1) + i;
                var d = (tubularSegments + 1) * j + i;
                // faces
                indices.push(a, b, d);
                indices.push(b, c, d);
            }
        }
        _this = _super.call(this, vertices, indices, normals, null, uvs) || this;
        return _this;
    }
    return TorusGeometry;
}(Geometry));

var LightMaterial = /** @class */ (function (_super) {
    __extends(LightMaterial, _super);
    function LightMaterial(parameters) {
        var _this = _super.call(this, parameters) || this;
        _this._instanceType = "LightMaterial";
        _this._lightAffect = true;
        return _this;
    }
    LightMaterial.prototype.clone = function () {
        return new LightMaterial().copy(this);
    };
    return LightMaterial;
}(BaseMaterial));

// precision mediump float;
// precision mediump int;
//
// uniform mat4 uViewMatrix;
// uniform mat4 uProjectionMatrix;
// uniform mat4 uModelMatrix;
var defaultVertexShader3d = "attribute vec3 aPosition;\nuniform mat4 uViewMatrix;\nuniform mat4 uProjectionMatrix;\nuniform mat4 uModelMatrix;\nvoid main() {\n    gl_Position = uProjectionMatrix * uViewMatrix * uModelMatrix * vec4( aPosition, 1.0 );\n}";
var defaultFragmentShader3d = "void main() {\n    gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}";
/**
 * 不考虑宏定义，否则自行修改getShader及缓存方式
 * 这三个必备，除非自己不需要几何的矩阵信息
 * uniform mat4 uViewMatrix;
 * uniform mat4 uProjectionMatrix;
 * uniform mat4 uModelMatrix;
 */
var ShaderMaterial = /** @class */ (function (_super) {
    __extends(ShaderMaterial, _super);
    function ShaderMaterial(vertexShader, fragmentShader, uniforms) {
        if (vertexShader === void 0) { vertexShader = defaultVertexShader3d; }
        if (fragmentShader === void 0) { fragmentShader = defaultFragmentShader3d; }
        if (uniforms === void 0) { uniforms = {}; }
        var _this = _super.call(this) || this;
        _this.vertexShader = vertexShader;
        _this.fragmentShader = fragmentShader;
        _this.uniforms = uniforms;
        /**
         * 是否用线框形式绘制
         */
        _this.wireframe = false;
        /**
         * 材质渲染面
         */
        _this.side = RenderSideType.FrontSide;
        /**
         * key就是渲染器唯一id
         */
        _this.shaders = {};
        _this.vertexShader = vertexShader || defaultVertexShader3d;
        _this.fragmentShader = fragmentShader || defaultFragmentShader3d;
        _this._instanceType = "ShaderMaterial";
        return _this;
    }
    Object.defineProperty(ShaderMaterial.prototype, "isShaderMaterial", {
        /**
         * 标记下。
         * 本来想直接用_instanceType判断，但是后续考虑到SpriteMaterial，SkyMaterial都会继承这个，会重写_instanceType
         */
        get: function () {
            return true;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * 自定义着色器不考虑缓存了，自己注意，
     * 多个完全一样的自定义材质，用同一个就行了
     * @param renderer
     */
    ShaderMaterial.prototype.getShader = function (renderer) {
        var id = renderer.CONTEXT_UID;
        if (!this.shaders[id]) {
            //生成
            this.shaders[id] = new GLShader(renderer.gl, this.vertexShader, this.fragmentShader);
            this.shaders[id]["_glShaderKey"] = "customShader" + ("id" + id) + ("instanceId" + this.instanceId);
        }
        return this.shaders[id];
    };
    ShaderMaterial.prototype.destroy = function () {
        for (var id in this.shaders) {
            this.shaders[id].destroy();
            delete this.shaders[id];
        }
        this.shaders = null;
        this.vertexShader = null;
        this.fragmentShader = null;
    };
    return ShaderMaterial;
}(HashObject));
var UniformType;
(function (UniformType) {
    UniformType["float"] = "f";
    /**
     * 纹理对象
     */
    UniformType["texture"] = "t";
    /**
     * 十六进制数字
     */
    UniformType["color"] = "c";
    /**
     * v2对象
     */
    UniformType["vector2"] = "v2";
    /**
     * v3对象
     */
    UniformType["vector3"] = "v3";
    /**
     * v4对象
     */
    UniformType["vector4"] = "v4";
    /**
     * m4对象
     */
    UniformType["matrix4"] = "m4";
    /**
     * m3对象
     */
    UniformType["matrix3"] = "m3";
    /**
     * 其他类型，不转换，直接赋值
     */
    UniformType["any"] = "any";
})(UniformType || (UniformType = {}));

var sprite3dVertexShader = "precision mediump float;\nattribute vec3 aPosition;\nattribute vec2 aTextureCoord;\nvarying vec2 vTextureCoord;\nuniform mat4 uViewMatrix;\nuniform mat4 uProjectionMatrix;\nuniform mat4 uModelMatrix;\n\nuniform vec2 center;\n\nuniform float rotation;\n\nuniform mat3 uvTransform;\n\nvoid main() {\n    vTextureCoord = ( uvTransform * vec3( aTextureCoord, 1 ) ).xy;\n    vec4 mvPosition = uViewMatrix * uModelMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n    vec2 scale;\n\tscale.x = length( vec3( uModelMatrix[ 0 ].x, uModelMatrix[ 0 ].y, uModelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( uModelMatrix[ 1 ].x, uModelMatrix[ 1 ].y, uModelMatrix[ 1 ].z ) );\n    \n    #ifndef USE_SIZEATTENUATION\n        bool isPerspective = ( uProjectionMatrix[ 2 ][ 3 ] == - 1.0 );\n        if ( isPerspective ) scale *= - mvPosition.z;\n    #endif\n\n    vec2 alignedPosition = ( aPosition.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\n\tmvPosition.xy += rotatedPosition;\n\n\tgl_Position = uProjectionMatrix * mvPosition;\n}";
var sprite3dFragmentShader = "precision mediump float;\nuniform vec3 color;\nuniform float alpha;\nuniform sampler2D map;\nuniform vec4 uFrameUvs;\nvarying vec2 vTextureCoord;\nvoid main() {\n    vec4 mapColor = texture2D( map, vTextureCoord );\n    vec2 s = step(vec2(uFrameUvs.x,uFrameUvs.y),vTextureCoord) - step(vec2(uFrameUvs.z,uFrameUvs.w),vTextureCoord);\n    mapColor *= abs(s.x * s.y);\n    gl_FragColor = vec4( color*alpha, alpha )*mapColor;\n}";
var Sprite3dMaterial = /** @class */ (function (_super) {
    __extends(Sprite3dMaterial, _super);
    function Sprite3dMaterial() {
        var _this = _super.call(this, sprite3dVertexShader, sprite3dFragmentShader, {
            center: { type: UniformType.vector2, value: new Vector2(0.5, 0.5) },
            rotation: { type: UniformType.float, value: 0.0 },
            color: { type: UniformType.color, value: 0xffffff },
            alpha: { type: UniformType.float, value: 1.0 },
            map: { type: UniformType.texture, value: Texture.WHITE },
            uvTransform: { type: UniformType.matrix3, value: new Matrix() },
            uFrameUvs: { type: UniformType.any, value: [0, 0, 1, 1] },
        }) || this;
        _this.sizeAttenuation = true;
        _this._instanceType = "Sprite3dMaterial";
        return _this;
    }
    Sprite3dMaterial.prototype.getShader = function (renderer) {
        var id = "" + renderer.CONTEXT_UID + this.sizeAttenuation;
        if (!this.shaders[id]) {
            //生成
            this.shaders[id] = new GLShader(renderer.gl, (this.sizeAttenuation ? '#define USE_SIZEATTENUATION\n' : "") + this.vertexShader, this.fragmentShader);
            this.shaders[id]["_glShaderKey"] = "customShader" + ("id" + id) + ("instanceId" + this.instanceId) + ("sizeAttenuation" + this.sizeAttenuation);
        }
        return this.shaders[id];
    };
    Object.defineProperty(Sprite3dMaterial.prototype, "center", {
        get: function () {
            return this.uniforms.center.value;
        },
        set: function (v) {
            this.uniforms.center.value = v;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Sprite3dMaterial.prototype, "rotation", {
        get: function () {
            return this.uniforms.rotation.value * RAD_TO_DEG;
        },
        set: function (v) {
            this.uniforms.rotation.value = v * DEG_TO_RAD;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Sprite3dMaterial.prototype, "color", {
        get: function () {
            return this.uniforms.color.value;
        },
        set: function (v) {
            this.uniforms.color.value = v;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Sprite3dMaterial.prototype, "alpha", {
        get: function () {
            return this.uniforms.alpha.value;
        },
        set: function (v) {
            this.uniforms.alpha.value = v;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Sprite3dMaterial.prototype, "map", {
        get: function () {
            return this.uniforms.map.value;
        },
        set: function (v) {
            this.uniforms.map.value = v;
            //纹理坐标矩阵
            //没加的加一个
            if (!v.transform)
                v.transform = new TextureMatrix(v);
            //更新下
            v.transform.update();
            //赋值偏移
            this.uniforms.uvTransform.value.copy(v.transform.mapCoord);
            //对于透明像素有裁切的
            var _a = v._uvs, x0 = _a.x0, y0 = _a.y0, x2 = _a.x2, y2 = _a.y2;
            this.uniforms.uFrameUvs.value = [x0, y0, x2, y2];
        },
        enumerable: false,
        configurable: true
    });
    return Sprite3dMaterial;
}(ShaderMaterial));

var AmbientLight = /** @class */ (function (_super) {
    __extends(AmbientLight, _super);
    function AmbientLight(color, intensity) {
        var _this = _super.call(this, color, intensity) || this;
        _this._instanceType = "AmbientLight";
        return _this;
    }
    return AmbientLight;
}(Light));

var OrthographicCamera = /** @class */ (function (_super) {
    __extends(OrthographicCamera, _super);
    function OrthographicCamera(left, right, top, bottom, near, far) {
        if (left === void 0) { left = -1; }
        if (right === void 0) { right = 1; }
        if (top === void 0) { top = 1; }
        if (bottom === void 0) { bottom = -1; }
        if (near === void 0) { near = 0.1; }
        if (far === void 0) { far = 2000; }
        var _this = _super.call(this) || this;
        _this.left = left;
        _this.right = right;
        _this.top = top;
        _this.bottom = bottom;
        _this.near = near;
        _this.far = far;
        _this._instanceType = 'OrthographicCamera';
        _this.zoom = 1;
        _this.updateProjectionMatrix();
        return _this;
    }
    OrthographicCamera.prototype.set = function (left, right, top, bottom, near, far) {
        if (near === void 0) { near = 0.1; }
        if (far === void 0) { far = 2000; }
        this.zoom = 1;
        this.left = left;
        this.right = right;
        this.top = top;
        this.bottom = bottom;
        this.near = near;
        this.far = far;
        this.updateProjectionMatrix();
    };
    OrthographicCamera.prototype.copy = function (source, recursive) {
        if (recursive === void 0) { recursive = true; }
        _super.prototype.copy.call(this, source, recursive);
        this.left = source.left;
        this.right = source.right;
        this.top = source.top;
        this.bottom = source.bottom;
        this.near = source.near;
        this.far = source.far;
        this.zoom = source.zoom;
        this.updateProjectionMatrix();
        return this;
    };
    OrthographicCamera.prototype.clone = function () {
        return new OrthographicCamera().copy(this);
    };
    OrthographicCamera.prototype.updateProjectionMatrix = function () {
        var dx = (this.right - this.left) / (2 * this.zoom);
        var dy = (this.top - this.bottom) / (2 * this.zoom);
        var cx = (this.right + this.left) / 2;
        var cy = (this.top + this.bottom) / 2;
        var left = cx - dx;
        var right = cx + dx;
        var top = cy + dy;
        var bottom = cy - dy;
        this.projectionMatrix.setOrtho(left, right, top, bottom, this.near, this.far);
        this.projectionMatrixInverse.setInverseOf(this.projectionMatrix);
    };
    return OrthographicCamera;
}(Camera));

var LightShadow = /** @class */ (function (_super) {
    __extends(LightShadow, _super);
    function LightShadow(camera) {
        var _this = _super.call(this) || this;
        _this.camera = camera;
        _this.bias = 0;
        _this.radius = 1;
        _this.mapSize = new Vector2(512, 512);
        _this.matrix = new Matrix4();
        _this._instanceType = "LightShadow";
        return _this;
    }
    LightShadow.prototype.copy = function (source) {
        this.camera = source.camera.clone();
        this.bias = source.bias;
        this.radius = source.radius;
        this.mapSize.copy(source.mapSize);
        return this;
    };
    /**
     * 子类继承修改为自己的
     * @param source
     */
    LightShadow.prototype.clone = function () {
        return new LightShadow().copy(this);
    };
    LightShadow.prototype.destroy = function () {
        this.mapSize = null;
        this.camera.destroy();
        this.camera = null;
    };
    return LightShadow;
}(HashObject));

var DirectionalLightShadow = /** @class */ (function (_super) {
    __extends(DirectionalLightShadow, _super);
    function DirectionalLightShadow() {
        return _super.call(this, new OrthographicCamera(-5, 5, 5, -5, 0.5, 500)) || this;
    }
    DirectionalLightShadow.prototype.clone = function () {
        return new DirectionalLightShadow().copy(this);
    };
    return DirectionalLightShadow;
}(LightShadow));

var DirectionalLight = /** @class */ (function (_super) {
    __extends(DirectionalLight, _super);
    function DirectionalLight(color, intensity) {
        var _this = _super.call(this, color, intensity) || this;
        _this._instanceType = "DirectionalLight";
        //位置默认一个
        _this.position.copy(Object3D.DefaultUp);
        // this.updateMatrix();
        _this.updateLocalMatrix();
        //目标默认一个，算方向用
        _this.target = new Object3D();
        _this.shadow = new DirectionalLightShadow();
        return _this;
    }
    DirectionalLight.prototype.copy = function (directionalLight) {
        _super.prototype.copy.call(this, directionalLight);
        this.target = directionalLight.target.clone();
        return this;
    };
    return DirectionalLight;
}(Light));

var PointLight = /** @class */ (function (_super) {
    __extends(PointLight, _super);
    /**
     *
     * @param color 颜色值，0到1的矢量
     * @param intensity 强度
     * @param distance 最大影响距离
     * @param decay 衰减系数，//多试试2
     */
    function PointLight(color, intensity, distance, decay) {
        if (distance === void 0) { distance = 0; }
        if (decay === void 0) { decay = 1; }
        var _this = _super.call(this, color, intensity) || this;
        _this.distance = distance;
        _this.decay = decay;
        _this._instanceType = "PointLight";
        return _this;
    }
    Object.defineProperty(PointLight.prototype, "power", {
        get: function () {
            return this.intensity * 4 * Math.PI;
        },
        set: function (value) {
            this.intensity = value / (4 * Math.PI);
        },
        enumerable: false,
        configurable: true
    });
    PointLight.prototype.copy = function (pointLight) {
        _super.prototype.copy.call(this, pointLight);
        this.distance = pointLight.distance;
        this.decay = pointLight.decay;
        return this;
    };
    return PointLight;
}(Light));

var AxesHelper = /** @class */ (function (_super) {
    __extends(AxesHelper, _super);
    function AxesHelper(size) {
        if (size === void 0) { size = 1; }
        var _this = this;
        var vertices = [
            0, 0, 0, size, 0, 0,
            0, 0, 0, 0, size, 0,
            0, 0, 0, 0, 0, size
        ];
        var colors = [
            1, 0, 0, 1, 0.6, 0,
            0, 1, 0, 0.6, 1, 0,
            0, 0, 1, 0, 0.6, 1
        ];
        var geometry = new Geometry(vertices, null, null, colors);
        var material = new BaseMaterial({ wireframe: true, useVertexColor: true });
        _this = _super.call(this, geometry, material) || this;
        return _this;
    }
    return AxesHelper;
}(Mesh3D));

var GridHelper = /** @class */ (function (_super) {
    __extends(GridHelper, _super);
    function GridHelper(size, divisions, color1, color2) {
        if (size === void 0) { size = 10; }
        if (divisions === void 0) { divisions = 10; }
        if (color1 === void 0) { color1 = 0x444444; }
        if (color2 === void 0) { color2 = 0x888888; }
        var _this = this;
        var center = divisions / 2;
        var step = size / divisions;
        var halfSize = size / 2;
        var colorArr1 = hex2rgb$1(color1);
        var colorArr2 = hex2rgb$1(color2);
        var vertices = [], colors = [];
        for (var i = 0, j = 0, k = -halfSize; i <= divisions; i++, k += step) {
            vertices.push(-halfSize, 0, k, halfSize, 0, k);
            vertices.push(k, 0, -halfSize, k, 0, halfSize);
            var color = i === center ? colorArr1 : colorArr2;
            var count = 4;
            while (count--) {
                colors.push(color[0], color[1], color[2]);
            }
        }
        var geometry = new Geometry(vertices, null, null, colors);
        var material = new BaseMaterial({ wireframe: true, useVertexColor: true });
        _this = _super.call(this, geometry, material) || this;
        return _this;
    }
    return GridHelper;
}(Mesh3D));

var Box3Helper = /** @class */ (function (_super) {
    __extends(Box3Helper, _super);
    function Box3Helper(box, color) {
        if (color === void 0) { color = 0xffff00; }
        var _this = this;
        var indices = [0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7];
        var positions = [1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1];
        _this = _super.call(this, new Geometry(positions, indices), new BaseMaterial({ wireframe: true, color: color })) || this;
        _this.box = box;
        _this.mouseChildren = _this.mouseEnable = false;
        return _this;
    }
    Box3Helper.prototype.updateWorldMatrix = function (updateParents, updateChildren) {
        if (updateParents === void 0) { updateParents = false; }
        if (updateChildren === void 0) { updateChildren = true; }
        var box = this.box;
        if (box.isEmpty())
            return;
        box.getCenter(this.position);
        box.getSize(this.scale);
        this.scale.multiplyScalar(0.5);
        _super.prototype.updateWorldMatrix.call(this, updateParents, updateChildren);
    };
    return Box3Helper;
}(Mesh3D));

/**
 * 根据渲染器，材质，灯光获取着色器
 * @param render
 * @param material
 * @param lights
 */
function getCusShader(render, material, lights, mesh, maxBones, useVertexTexture, fog, shadow) {
    //所有参数
    var parameters = {
        glUid: render.CONTEXT_UID,
        precision: getMaxPrecision(render),
        pointLightsNum: lights.pointLights.length,
        dirLightsNum: lights.directionalLights.length,
        morphTargets: mesh.morphTargetInfluences && material.morphTargets,
        morphNormals: mesh.morphTargetInfluences && material.morphTargets && material.morphNormals,
        skinning: material.skinning && maxBones > 0,
        maxBones: maxBones || 0,
        useVertexTexture: useVertexTexture,
        lightAffect: material._lightAffect,
        useMap: !!material.map && material.map.valid,
        // @ts-ignore
        useNormalMap: !!material.normalMap && material.normalMap.valid,
        useEnvMap: !!material.envMap && material.envMap.valid,
        combine: material.combine,
        useVertexColor: !!material.useVertexColor,
        useFog: fog && material.useFog,
        useShadow: shadow && mesh.receiveShadow && material._lightAffect,
        shadowType: shadow && shadow.shadowType,
    };
    //计算code，
    var shaderKey = getShaderKey(parameters);
    var cusShader;
    for (var i = 0; i < cacheShaders.length; i++) {
        if (cacheShaders[i]._glShaderKey === shaderKey) {
            cusShader = cacheShaders[i];
            ++cusShader.usedTimes;
            break;
        }
    }
    if (!cusShader) {
        cusShader = new CusShader(render.gl, parameters);
        cusShader._glShaderKey = shaderKey;
        //存下
        cacheShaders.push(cusShader);
    }
    return cusShader;
}
/**
 * 根据参数获取shaderKey
 * @param parameters
 */
function getShaderKey(parameters) {
    var array = [];
    for (var i = 0; i < parameterNames.length; i++) {
        array.push(parameters[parameterNames[i]]);
    }
    return array.join();
}
//根据渲染器的上下文id缓存的最大精度
var maxPrecisionCache = {};
/**
 * 获取最大精度，暂时不考虑缓存，性能有问题再说TODO
 * @param gl
 */
function getMaxPrecision(render) {
    if (!maxPrecisionCache[render.CONTEXT_UID]) {
        maxPrecisionCache[render.CONTEXT_UID] = (function () {
            var gl = render.gl;
            if (gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.HIGH_FLOAT).precision > 0 &&
                gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT).precision > 0) {
                return 'highp';
            }
            if (gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.MEDIUM_FLOAT).precision > 0 &&
                gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT).precision > 0) {
                return 'mediump';
            }
            return 'lowp';
        })();
    }
    return maxPrecisionCache[render.CONTEXT_UID];
}
var CusShader = /** @class */ (function (_super) {
    __extends(CusShader, _super);
    /**
     *
     * @param gl
     * @param parameters
     */
    function CusShader(gl, parameters) {
        var _this = this;
        //预处理参数
        var frontVert = [
            'precision ' + parameters.precision + ' float;',
            'precision ' + parameters.precision + ' int;',
            parameters.lightAffect ? '#define USE_LIGHT' : '',
            parameters.morphTargets ? '#define USE_MORPHTARGETS' : '',
            parameters.morphNormals ? '#define USE_MORPHNORMALS' : '',
            parameters.skinning ? '#define USE_SKINNING' : '',
            parameters.useVertexTexture ? '#define BONE_TEXTURE' : '',
            '#define MAX_BONES ' + parameters.maxBones,
            parameters.useMap ? '#define USE_MAP' : '',
            parameters.useNormalMap ? '#define USE_NORMAL_MAP' : '',
            parameters.useEnvMap ? '#define USE_ENVMAP' : '',
            parameters.useVertexColor ? '#define USE_VERTEXCOLOR' : '',
            parameters.useFog ? '#define USE_FOG' : '',
            parameters.useShadow ? '#define USE_SHADOW' : '',
        ].filter(function (e) { return e !== ''; }).join('\n');
        //不为空加个换行
        if (frontVert)
            frontVert += "\n";
        var frontFrag = [
            parameters.useNormalMap ? '#extension GL_OES_standard_derivatives : enable' : '',
            'precision ' + parameters.precision + ' float;',
            'precision ' + parameters.precision + ' int;',
            parameters.lightAffect ? '#define USE_LIGHT' : '',
            parameters.useMap ? '#define USE_MAP' : '',
            parameters.useNormalMap ? '#define USE_NORMAL_MAP' : '',
            parameters.useEnvMap ? '#define USE_ENVMAP' : '',
            parameters.useEnvMap ? '#define ' + parameters.combine : '',
            parameters.useVertexColor ? '#define USE_VERTEXCOLOR' : '',
            parameters.useFog ? '#define USE_FOG' : '',
            parameters.useShadow ? '#define USE_SHADOW' : '',
            parameters.useShadow ? '#define ' + parameters.shadowType : '',
        ].filter(function (e) { return e !== ''; }).join('\n');
        if (frontFrag)
            frontFrag += "\n";
        var frag = FRAG
            .replace(new RegExp(shaderReplaceStr.POINT_LIGHTS_NUM, "gm"), parameters.pointLightsNum + "")
            .replace(new RegExp(shaderReplaceStr.DIR_LIGHTS_NUM, "gm"), parameters.dirLightsNum + "");
        _this = _super.call(this, gl, frontVert + VERT, frontFrag + frag) || this;
        //这两个需要重写下
        //修改uniform
        _this.uniformData = extractUniforms(gl, _this.program);
        //是否需要按照链式的点下去，链式的能点下去吧，但是数组索引自己拼字段
        _this.uniforms = generateUniformAccessObject(gl, _this.uniformData);
        //以后用
        _this.usedTimes = 0;
        return _this;
    }
    return CusShader;
}(GLShader));
//部分属性不清除中括号（比如光照数据，链式结构赋值），
//有些清掉中括号，传纯数字数组（比如纹理通道数量uSamplers，变形权重morphTargetInfluences）
//复制一个不清除中括号的
function extractUniforms(gl, program) {
    var uniforms = {};
    var totalUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
    for (var i = 0; i < totalUniforms; i++) { //morphTargetInfluences
        var uniformData = gl.getActiveUniform(program, i);
        //morphTargetInfluences直接传一个数组吧，还是说不区分，也直接按morphTargetInfluences[0]传
        var name = (uniformData.name.indexOf("morphTargetInfluences") == 0 || uniformData.name.indexOf("uBoneMatrices") == 0) ?
            uniformData.name.replace(/\[.*?\]/, "") : uniformData.name;
        var type = mapType(gl, uniformData.type);
        // console.log(name)
        uniforms[name] = {
            type: type,
            size: uniformData.size,
            location: gl.getUniformLocation(program, name),
            value: defaultValue(type, uniformData.size)
        };
    }
    return uniforms;
}
/**
 * 存储用过着色器程序
 * 根据自己的code取，code根据参数拼
 * 用数组吧，考虑为啥不用对象键值
 */
var cacheShaders = [];
//////////////ShaderParametersInt和parameterNames这两个要对应的，否则缓存会出问题
/**
 * 影响着色器编译的所有的参数
 *
 * 正反面影响法线和光照，还需要定义正反面光照及两面光照，以后再说
 * 环境贴图也需要法线，不止是光照需要，以后再说，到时normal必传吧
 */
var parameterNames = [
    "glUid",
    "precision",
    "pointLightsNum",
    "dirLightsNum",
    "morphTargets",
    "morphNormals",
    "skinning",
    "maxBones",
    "useVertexTexture",
    "lightAffect",
    "useMap",
    "useNormalMap",
    "useEnvMap",
    "combine",
    "useVertexColor",
    "useFog",
    "useShadow",
    "shadowType",
];
/**
 * 着色器替换的一些文案
 */
var shaderReplaceStr;
(function (shaderReplaceStr) {
    shaderReplaceStr["POINT_LIGHTS_NUM"] = "POINT_LIGHTS_NUM";
    shaderReplaceStr["DIR_LIGHTS_NUM"] = "DIR_LIGHTS_NUM";
})(shaderReplaceStr || (shaderReplaceStr = {}));
var VERT = [
    "attribute vec3 aPosition;",
    // "attribute vec3 aColor;",//顶点颜色数据
    // "attribute vec2 aTextureCoord;",//纹理坐标，
    // 'attribute vec3 aNormal;',//法线数据会和上述三个放在同一个数组里，但是不一定进attribute通道
    "uniform mat4 uViewMatrix;",
    "uniform mat4 uProjectionMatrix;",
    "uniform mat4 uModelMatrix;",
    // "uniform mat4 uNormalMatrix;",//模型矩阵uModelMatrix的逆的转置，若正交就是模型矩阵，估计还要乘上视图举证，外面乘，先乘再逆转置
    "#ifdef USE_VERTEXCOLOR",
    "   attribute vec3 aColor;",
    "   varying vec3 vColor;",
    "#endif",
    //是否使用贴图
    "   #if defined(USE_MAP) || defined(USE_NORMAL_MAP)",
    "   attribute vec2 aTextureCoord;",
    "   varying vec2 vTextureCoord;",
    "   uniform mat3 uUvTransform;",
    "#endif",
    //使用环境贴图或灯光
    '#if defined( USE_ENVMAP ) || defined( USE_LIGHT )',
    '   attribute vec3 aNormal;',
    "   uniform mat4 uNormalMatrix;",
    "   varying vec3 vNormal;",
    "   varying vec3 vWorldPosition;",
    "   varying vec3 vViewPosition;",
    '#endif',
    //环境贴图需要变量
    "#ifdef USE_ENVMAP",
    "   varying vec3 vReflect;",
    "   uniform vec3 uCameraPosition;",
    '#endif',
    //使用骨骼蒙皮
    "#ifdef USE_SKINNING",
    "   uniform mat4 uBindMatrix;",
    "   uniform mat4 uBindMatrixInverse;",
    "   #ifdef BONE_TEXTURE",
    "      uniform sampler2D uBoneTexture;",
    "      uniform int uBoneTextureSize;",
    "      mat4 getBoneMatrix( const in float i ) {",
    "         float j = i * 4.0;",
    "         float x = mod( j, float( uBoneTextureSize ) );",
    "         float y = floor( j / float( uBoneTextureSize ) );",
    "         float dx = 1.0 / float( uBoneTextureSize );",
    "         float dy = 1.0 / float( uBoneTextureSize );",
    "         y = dy * ( y + 0.5 );",
    "         vec4 v1 = texture2D( uBoneTexture, vec2( dx * ( x + 0.5 ), y ) );",
    "         vec4 v2 = texture2D( uBoneTexture, vec2( dx * ( x + 1.5 ), y ) );",
    "         vec4 v3 = texture2D( uBoneTexture, vec2( dx * ( x + 2.5 ), y ) );",
    "         vec4 v4 = texture2D( uBoneTexture, vec2( dx * ( x + 3.5 ), y ) );",
    "         mat4 bone = mat4( v1, v2, v3, v4 );",
    "         return bone;",
    "      }",
    "   #else",
    "      uniform mat4 uBoneMatrices[ MAX_BONES ];",
    "      mat4 getBoneMatrix( const in float i ) {",
    "         mat4 bone = uBoneMatrices[ int(i) ];",
    "         return bone;",
    "      }",
    "   #endif",
    '	attribute vec4 aSkinIndex;',
    '	attribute vec4 aSkinWeight;',
    "#endif",
    //变形顶点数据，单独建数组传，还是放入vao
    '#ifdef USE_MORPHTARGETS',
    '	attribute vec3 morphTarget0;',
    '	attribute vec3 morphTarget1;',
    '	attribute vec3 morphTarget2;',
    '	attribute vec3 morphTarget3;',
    '	#ifdef USE_MORPHNORMALS',
    '		attribute vec3 morphNormal0;',
    '		attribute vec3 morphNormal1;',
    '		attribute vec3 morphNormal2;',
    '		attribute vec3 morphNormal3;',
    "       uniform float morphTargetInfluences[ 4 ];",
    '	#else',
    '		attribute vec3 morphTarget4;',
    '		attribute vec3 morphTarget5;',
    '		attribute vec3 morphTarget6;',
    '		attribute vec3 morphTarget7;',
    "       uniform float morphTargetInfluences[ 8 ];",
    '	#endif',
    '#endif',
    //雾化
    '#ifdef USE_FOG',
    '    varying float vFogDepth;',
    '#endif',
    //阴影
    '#ifdef USE_SHADOW',
    // `   #if ${shaderReplaceStr.DIR_LIGHTS_NUM} > 0`,
    '      uniform mat4 uDirectionalShadowMatrix;',
    '      varying vec4 vDirectionalShadowCoord;',
    // '   #endif',
    '#endif',
    "void main() {",
    //赋值顶点坐标
    "   vec3 transformed = vec3( aPosition );",
    //考虑变形,顶点位置
    "   #ifdef USE_MORPHTARGETS",
    "      transformed += ( morphTarget0 - aPosition ) * morphTargetInfluences[ 0 ];",
    "      transformed += ( morphTarget1 - aPosition ) * morphTargetInfluences[ 1 ];",
    "      transformed += ( morphTarget2 - aPosition ) * morphTargetInfluences[ 2 ];",
    "      transformed += ( morphTarget3 - aPosition ) * morphTargetInfluences[ 3 ];",
    "      #ifndef USE_MORPHNORMALS",
    "         transformed += ( morphTarget4 - aPosition ) * morphTargetInfluences[ 4 ];",
    "         transformed += ( morphTarget5 - aPosition ) * morphTargetInfluences[ 5 ];",
    "         transformed += ( morphTarget6 - aPosition ) * morphTargetInfluences[ 6 ];",
    "         transformed += ( morphTarget7 - aPosition ) * morphTargetInfluences[ 7 ];",
    "      #endif",
    "   #endif",
    //使用蒙皮骨骼
    "   #ifdef USE_SKINNING",
    "      mat4 boneMatX = getBoneMatrix( aSkinIndex.x );",
    "      mat4 boneMatY = getBoneMatrix( aSkinIndex.y );",
    "      mat4 boneMatZ = getBoneMatrix( aSkinIndex.z );",
    "      mat4 boneMatW = getBoneMatrix( aSkinIndex.w );",
    "      vec4 skinVertex = uBindMatrix * vec4( transformed, 1.0 );",
    "      vec4 skinned = vec4( 0.0 );",
    "      skinned += boneMatX * skinVertex * aSkinWeight.x;",
    "      skinned += boneMatY * skinVertex * aSkinWeight.y;",
    "      skinned += boneMatZ * skinVertex * aSkinWeight.z;",
    "      skinned += boneMatW * skinVertex * aSkinWeight.w;",
    "      transformed = ( uBindMatrixInverse * skinned ).xyz;",
    "   #endif",
    //常规的
    "   vec4 mvPosition = uViewMatrix * uModelMatrix * vec4( transformed, 1.0 );",
    "   gl_Position = uProjectionMatrix * mvPosition;",
    //使用顶点颜色
    "   #ifdef USE_VERTEXCOLOR",
    "      vColor = aColor;",
    "   #endif",
    //纹理坐标
    "   #if defined(USE_MAP) || defined(USE_NORMAL_MAP)",
    // "      vTextureCoord = aTextureCoord;",
    "      vTextureCoord = ( uUvTransform * vec3( aTextureCoord, 1 ) ).xy;",
    "   #endif",
    //使用环境贴图或灯光
    '   #if defined( USE_ENVMAP ) || defined( USE_LIGHT )',
    "         vec3 objectNormal = vec3( aNormal );",
    //考虑变形，法线
    "      #ifdef USE_MORPHNORMALS",
    "         objectNormal += ( morphNormal0 - aNormal ) * morphTargetInfluences[ 0 ];",
    "         objectNormal += ( morphNormal1 - aNormal ) * morphTargetInfluences[ 1 ];",
    "         objectNormal += ( morphNormal2 - aNormal ) * morphTargetInfluences[ 2 ];",
    "         objectNormal += ( morphNormal3 - aNormal ) * morphTargetInfluences[ 3 ];",
    "      #endif",
    //骨骼蒙皮
    "      #ifdef USE_SKINNING",
    "         mat4 skinMatrix = mat4( 0.0 );",
    "         skinMatrix += aSkinWeight.x * boneMatX;",
    "         skinMatrix += aSkinWeight.y * boneMatY;",
    "         skinMatrix += aSkinWeight.z * boneMatZ;",
    "         skinMatrix += aSkinWeight.w * boneMatW;",
    "         skinMatrix  = uBindMatrixInverse * skinMatrix * uBindMatrix;",
    "         objectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;",
    "      #endif",
    "      vViewPosition = -mvPosition.xyz;",
    "      vWorldPosition = vec3(uModelMatrix * vec4(transformed,1.0));",
    "      vec3 vTransformedNormal = vec3(uNormalMatrix * vec4(objectNormal,1.0));",
    "      vNormal = normalize(vTransformedNormal);",
    //环境贴图
    "      #ifdef USE_ENVMAP",
    "         vec3 cameraToVertex = normalize( vWorldPosition.xyz - uCameraPosition );",
    "         vec3 worldNormal = normalize( ( vec4( vTransformedNormal, 0.0 ) * uViewMatrix ).xyz );",
    "         vReflect = reflect(cameraToVertex, worldNormal);",
    '      #endif',
    '   #endif',
    //雾化深度
    '   #ifdef USE_FOG',
    '      vFogDepth = -mvPosition.z;',
    '   #endif',
    //阴影
    '   #ifdef USE_SHADOW',
    // `      #if ${shaderReplaceStr.DIR_LIGHTS_NUM} > 0`,
    '         vDirectionalShadowCoord = uDirectionalShadowMatrix * (uModelMatrix * vec4(transformed,1.0));',
    // '      #endif',
    '   #endif',
    "}"
].join("\n");
var FRAG = [
    //材质通用参数
    "uniform vec3 uMatColor;",
    "uniform float uMatAlpha;",
    // "#ifdef USE_MAP",
    "#ifdef USE_MAP",
    '   uniform sampler2D uMap;',
    "#endif",
    "#if defined(USE_MAP)  || defined( USE_NORMAL_MAP)",
    "   uniform vec4 uFrameUvs;",
    "   varying vec2 vTextureCoord;",
    "#endif",
    "#ifdef USE_VERTEXCOLOR",
    "   varying vec3 vColor;",
    "#endif",
    '#if defined( USE_ENVMAP ) || defined( USE_LIGHT ) || defined( USE_NORMAL_MAP) ',
    "   varying vec3 vNormal;",
    "   varying vec3 vWorldPosition;",
    "   varying vec3 vViewPosition;",
    "#endif",
    "#ifdef USE_ENVMAP",
    "   uniform sampler2D uEnvMap;",
    "   uniform float uReflectivity;",
    "   uniform mat4 uViewMatrix;",
    "   varying vec3 vReflect;",
    '#endif',
    "#ifdef USE_NORMAL_MAP",
    "uniform sampler2D uNormalMap;",
    "vec3 getNormalFromMap() {",
    // "return vec3(1.0, 1.0, 1.0);",
    "    vec3 tangentNormal = texture2D(uNormalMap, vTextureCoord).rgb * 2.0 - 1.0;",
    "    vec3 Q1  = dFdx(vViewPosition);",
    "    vec3 Q2  = dFdy(vViewPosition);",
    "    vec2 st1 = dFdx(vTextureCoord);",
    "    vec2 st2 = dFdy(vTextureCoord);",
    "    vec3 N  = normalize(vNormal);",
    "    vec3 T  = normalize(Q1 * st2.t - Q2 * st1.t);",
    "    vec3 B  = -normalize(cross(N, T));",
    "    mat3 TBN = mat3(T, B, N);",
    "    return normalize(TBN * tangentNormal);",
    "}",
    "#endif",
    //灯光参数
    '#ifdef USE_LIGHT',
    //计算镜面反射系数，前两个参数都应该是标准化过的
    "   float calcSpecular(vec3 lightDir, vec3 viewDir, vec3 normal) {",
    "      vec3 halfwayDir = normalize(lightDir + viewDir);",
    "      float spec = pow(max(dot(normal, halfwayDir), 0.0), 32.0);",
    "      return spec;",
    "   }",
    //点光源参数
    "   #if " + shaderReplaceStr.POINT_LIGHTS_NUM + " > 0",
    "      #define saturate(a) clamp( a, 0.0, 1.0 )",
    "      float calcLightAttenuation( float lightDistance, float cutoffDistance, float decayExponent ) {",
    "         if ( decayExponent > 0.0 ) {",
    "            return pow( saturate( - lightDistance / cutoffDistance + 1.0 ), decayExponent );",
    "         }",
    "         return 1.0;",
    "      }",
    "      struct PointLight {",
    "         vec3 color;",
    "         vec3 position;",
    "         float distance;",
    "         float decay;",
    "      };",
    "      uniform PointLight pointLights[" + shaderReplaceStr.POINT_LIGHTS_NUM + "];",
    "   #endif",
    //方向光参数
    "   #if " + shaderReplaceStr.DIR_LIGHTS_NUM + " > 0",
    "      struct DirectionalLight {",
    "         vec3 direction;",
    "         vec3 color;",
    "         int shadow;",
    "         float shadowBias;",
    "	      float shadowRadius;",
    "	      vec2 shadowMapSize;",
    "      };",
    "      uniform DirectionalLight directionalLights[" + shaderReplaceStr.DIR_LIGHTS_NUM + "];",
    "   #endif",
    //环境光
    "   uniform vec3 uAmbientLightColor;",
    '#endif',
    //雾化声明量
    '#ifdef USE_FOG',
    '   uniform vec3 uFogColor;',
    '   varying float vFogDepth;',
    // '   uniform float uFogDensity;',
    '   uniform float uFogNear;',
    '   uniform float uFogFar;',
    '#endif',
    //阴影
    "#ifdef USE_SHADOW",
    // `   #if ${shaderReplaceStr.DIR_LIGHTS_NUM} > 0`,
    '      uniform sampler2D uDirectionalShadowMap;',
    '      varying vec4 vDirectionalShadowCoord;',
    // '   #endif',
    '      const float UnpackDownscale = 255. / 256.;',
    '      const vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256.,  256. );',
    '      const vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );',
    '      float unpackRGBAToDepth( const in vec4 v ) {',
    '          return dot( v, UnpackFactors );',
    '      }',
    '   float texture2DCompare( sampler2D depths, vec2 uv, float compare ) {',
    '      return step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );',
    '   }',
    '   float getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {',
    '      float shadow = 1.0;',
    '      shadowCoord.xyz /= shadowCoord.w;',
    //如果要出于性能优化考虑，把除二+0.5可以放到cpu里，像three
    // '      shadowCoord.xyz = (shadowCoord.xyz/shadowCoord.w)/2.0 + 0.5;',
    '      shadowCoord.z += shadowBias;',
    '      bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );',
    '      bool inFrustum = all( inFrustumVec );',
    '      bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );',
    '      bool frustumTest = all( frustumTestVec );',
    '      if ( frustumTest ) {',
    '         #if defined( SHADOWMAP_TYPE_PCF )',
    '            vec2 texelSize = vec2( 1.0 ) / shadowMapSize;',
    '            float dx0 = - texelSize.x * shadowRadius;',
    '	         float dy0 = - texelSize.y * shadowRadius;',
    '	         float dx1 = + texelSize.x * shadowRadius;',
    '	         float dy1 = + texelSize.y * shadowRadius;',
    '            shadow =(',
    '               texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +',
    '               texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +',
    '               texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +',
    '               texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +',
    '               texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +',
    '               texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +',
    '               texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +',
    '               texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +',
    '               texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )',
    '            ) * ( 1.0 / 9.0 );',
    '         #elif defined( SHADOWMAP_TYPE_PCF_SOFT )',
    //这里暂时空。以后有需要再说
    '         #else',
    '            shadow = texture2DCompare(shadowMap, shadowCoord.xy, shadowCoord.z);',
    '         #endif',
    '      }',
    '      return shadow;',
    '   }',
    '#endif',
    "void main() {",
    //颜色计算，通用
    "   vec4 color = vec4( uMatColor, uMatAlpha );",
    "   color.rgb *= color.a;",
    //纹理颜色
    "   #ifdef USE_MAP",
    "      vec4 mapColor = texture2D( uMap, vTextureCoord );",
    "      color *= mapColor;",
    "      vec2 s = step(vec2(uFrameUvs.x, uFrameUvs.y),vTextureCoord) - step(vec2(uFrameUvs.z, uFrameUvs.w), vTextureCoord);",
    // "      vec2 s = step(vec2(0.6669921875,0.4111328125),vTextureCoord) - step(vec2(0.951171875,0.65625),vTextureCoord);",
    "      color *= abs(s.x * s.y);",
    "   #endif",
    "   vec3 normal = vNormal;",
    "   #ifdef USE_NORMAL_MAP",
    "       normal = getNormalFromMap();",
    "   #endif",
    //计算顶点颜色
    "   #ifdef USE_VERTEXCOLOR",
    "      color *= vec4(vColor,1.0);",
    "   #endif",
    "   vec3 colorRgb = color.rgb;",
    //光照颜色计算
    '   #ifdef USE_LIGHT',
    "      vec3 totalDiffuseLight = vec3( 0.0 );",
    "      vec3 totalSpecularLight = vec3( 0.0 );",
    "      vec3 viewDir = normalize(vViewPosition);",
    "      vec3 lightDirection;",
    "      float diffuse;",
    "      float specular;",
    //计算点光源
    "      #if " + shaderReplaceStr.POINT_LIGHTS_NUM + " > 0",
    "         float attenuation;",
    "         for ( int i = 0; i < " + shaderReplaceStr.POINT_LIGHTS_NUM + "; i ++ ) {",
    //漫反射
    "            lightDirection = pointLights[i].position + vViewPosition;",
    "            attenuation = calcLightAttenuation( length( lightDirection ), pointLights[ i ].distance, pointLights[ i ].decay );",
    "            lightDirection = normalize(lightDirection);",
    "            diffuse = max( dot( normal, lightDirection ), 0.0 );",
    // "            float pointDiffuseWeightHalf = max( 0.5 * dot( normal, lightDirection ) + 0.5, 0.0 );",
    // "            vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), vec3(0.75, 0.375, 0.1875) );",
    "            totalDiffuseLight += pointLights[i].color * (diffuse * attenuation);",
    //镜面反射
    // "            vec3 reflectDir = reflect(-lightDirection, normal);",// 计算反射方向向量
    // "            float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32.0);",//发散系数待定
    "            specular = calcSpecular(lightDirection,viewDir,normal);",
    "            totalSpecularLight += pointLights[i].color *(specular * attenuation);",
    "         }",
    "      #endif",
    //计算方向光
    "      #if " + shaderReplaceStr.DIR_LIGHTS_NUM + " > 0",
    '         DirectionalLight directionalLight;',
    "         for( int i = 0; i < " + shaderReplaceStr.DIR_LIGHTS_NUM + "; i++ ) {",
    '            directionalLight = directionalLights[ i ];',
    '            vec3 dColor = directionalLight.color;',
    '            #ifdef USE_SHADOW',
    '               dColor *= all( bvec2( directionalLight.shadow, 1.0 ) ) ? getShadow( uDirectionalShadowMap, directionalLight.shadowMapSize, directionalLight.shadowBias,directionalLight.shadowRadius, vDirectionalShadowCoord ) : 1.0;',
    '            #endif',
    //漫反射
    "            lightDirection = directionalLight.direction;",
    "            diffuse = max( dot( normal, lightDirection ), 0.0 );",
    // "            float dirDiffuseWeightHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );",
    // "            vec3 dirDiffuseWeight = mix( vec3 ( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), vec3(0.75, 0.375, 0.1875) );",
    "            totalDiffuseLight += dColor * diffuse;",
    //镜面反射，貌似没有，
    // "            vec3 reflectDir1 = reflect(-directionalLight.direction, normal);",//待测试，是否加负号
    // "            float spec1 = pow(max(dot(viewDir, reflectDir1), 0.0), 32.0);",
    "            specular = calcSpecular(lightDirection,viewDir,normal);",
    //阴影下，讲道理不会有镜面放射
    // "            specular *= step(shadow, 1.0); " +
    "            totalSpecularLight += dColor * specular;",
    "         }",
    "      #endif",
    //计算环境光颜色，是否要乘材质本身颜色，待定，效果待调整，镜面反射是否要乘color.rgb，
    "      colorRgb = (totalDiffuseLight + uAmbientLightColor + totalSpecularLight) * colorRgb;",
    '   #endif',
    //计算环境贴图
    '   #ifdef USE_ENVMAP',
    //这种情况，环境贴图有问题，不随相机改变
    // '	   vec3 reflectView = normalize( ( uViewMatrix * vec4( normalize( vReflect ), 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) );',
    // '	   vec2 envUv =  reflectView.xy * 0.5 + 0.5;',
    // '      envUv.y = 1.0- envUv.y;',//需要倒一下y
    //换种方式计算
    '      vec2 envUv;',
    "      vec3 reflectVec = normalize( vReflect );",
    "      envUv.y =0.5 - asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * 0.31830988618;",
    "      envUv.x = atan( reflectVec.z, reflectVec.x ) * 0.15915494 + 0.5;",
    //按照球坐标系计算，也正确，但是上面更简洁
    // 'vec3  rn=  normalize( vReflect );',
    // 'float l= atan(rn.x/rn.z);',//经度
    // 'float b = atan(rn.y/pow(1.0-rn.y*rn.y+0.001,0.5));',//纬度
    // "const float pp = 3.1415926;",
    // "if(rn.z == 0.0){",
    //    "l = sign(rn.x)*pp*0.5;",
    // "}else if(rn.z<0.0){",
    //    " l+= sign(rn.x)*pp;",
    // '}',
    // 'l = l/pp*0.5+0.25;',
    // 'l += step(0.0,-l);',
    // 'vec2 envUv = vec2(l,1.0-(b/3.1415926+0.5));',
    '	   vec4 envColor = texture2D( uEnvMap, envUv );',
    '      #ifdef ENVMAP_BLENDING_MULTIPLY',
    '         colorRgb = mix(colorRgb, colorRgb * envColor.xyz,  uReflectivity);',
    '      #elif defined( ENVMAP_BLENDING_MIX )',
    '         colorRgb = mix( colorRgb, envColor.xyz,   uReflectivity );',
    '      #elif defined( ENVMAP_BLENDING_ADD )',
    '         colorRgb += envColor.xyz  * uReflectivity;',
    '      #endif',
    '   #endif',
    '   gl_FragColor = vec4( colorRgb, color.a );',
    //雾化处理
    '#ifdef USE_FOG',
    // '   float fogFactor = 1.0 - clamp( exp2( - uFogDensity * uFogDensity * vFogDepth * vFogDepth * 1.442695 ), 0.0, 1.0 );',
    '   float fogFactor = smoothstep( uFogNear, uFogFar, vFogDepth );',
    '   gl_FragColor.rgb = mix( gl_FragColor.rgb, uFogColor*color.a, fogFactor );',
    '#endif',
    "}"
].join("\n");

//到时还要加上顶点变形的和骨骼变形的
var vertex = "attribute vec3 aPosition;\nuniform mat4 uLightSpaceMatrix;\nuniform mat4 uModelMatrix;\nvoid main() {\n    gl_Position = uLightSpaceMatrix * uModelMatrix * vec4( aPosition, 1.0 );\n}";
var fragment = "precision mediump float;\n    // uniform float uMatAlpha;\n    const vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256.,  256. );\n    vec4 packDepthToRGBA( const in float v ) {\n        vec4 r = vec4( fract( v * PackFactors ), v );\n        r.yzw -= r.xyz * (1. / 256.);\n        return r * (256. / 255.);\n    }\n    void main() {\n        // gl_FragColor = vec4( vec3( 1.0 - gl_FragCoord.z ), uMatAlpha );\n        gl_FragColor = packDepthToRGBA( gl_FragCoord.z );\n}";
var ShadowShader = /** @class */ (function (_super) {
    __extends(ShadowShader, _super);
    function ShadowShader(gl) {
        return _super.call(this, gl, vertex, fragment) || this;
    }
    return ShadowShader;
}(GLShader));

var tempVec3 = new Vector3();
var tempMatrix4 = new Matrix4();
//需要管理渲染的状态 resetToDefault  resetTo3D
var D3Renderer = /** @class */ (function (_super) {
    __extends(D3Renderer, _super);
    function D3Renderer(renderer) {
        var _this = _super.call(this, renderer) || this;
        _this.meshes = [];
        return _this;
    }
    D3Renderer.prototype.onContextChange = function () {
        var gl = this.renderer.gl;
        this.maxVertexUniforms = gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS);
        var maxVertexTextures = gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS);
        var vertexTextures = maxVertexTextures > 0;
        var floatFragmentTextures = !!gl.getExtension("OES_texture_float");
        //传入的数据纹理暂时有问题，是UNPACK_ALIGNMENT还是UNPACK_FLIP_Y_WEBGL的问题未知，所以不管先
        this.floatVertexTextures = vertexTextures && floatFragmentTextures;
    };
    D3Renderer.prototype.start = function () {
        //设置3d状态机属性
        // this.renderer.state.resetTo3D();
        //自行设置状态机，原先的有太多问题
        //允许深度检测
        this.renderer.state.setDepthTest(1);
        //混色模式重新设置
        // this.renderer.state.setBlendMode(BLEND_MODES.NORMAL_NPM);//让着色器里预乘
        //设置逆时针为正面，下面根据材质自行设置
        //this.renderer.state.setFrontFace(0);
        //设置剔除，下面根据材质自行设置
        //this.setCullFace(1);
    };
    D3Renderer.prototype.stop = function () {
        this.flush();
        //原先的视窗需要重新//讲道理应该渲染器自己搞，算了
        this.renderer._activeRenderTarget.activate();
        // this.renderer.rootRenderTarget.activate();
        this.renderer.state.setState(this.renderer.state.defaultState);
    };
    //继续需要的数据
    D3Renderer.prototype.render = function (obj) {
        if (!obj.geometry || !obj.material)
            return;
        var mat = obj.material;
        var meshes = this.meshes;
        //提取渲染对象及材质，分组渲染，怎么考虑同一个geometry只需要处理一次attr，
        //分组按
        // if (!this.meshes.length) {
        //     this.meshes.push(obj);
        // } else {
        var len = meshes.length;
        for (var i = 0; i < len; i++) {
            if (meshes[i].material == mat) { //没啥软用
                meshes.splice(i, 0, obj);
                return;
            }
        }
        // }
        meshes.push(obj);
    };
    D3Renderer.prototype.flush = function () {
        //生成一张阴影的深度贴图
        var shadow = getShadowMap(this.lightsConfig, this.meshes, this.renderer);
        if (shadow) {
            //绑定过帧缓存，viewport肯定被改了,该回去
            this.renderer.gl.viewport(this.viewport.x, this.viewport.y, this.viewport.width, this.viewport.height);
            //加阴影类型
            shadow.shadowType = this.shadowType;
        }
        //同一材质的模型一起处理，同一个着色器，webglRenderer里会判断，不会重复绑定
        var curShader = null;
        var pointLightNum = this.lightsConfig.pointLights.length;
        var dirLightNum = this.lightsConfig.directionalLights.length;
        var gl = this.renderer.gl;
        var textureManager = this.renderer.textureManager;
        for (var i = 0; i < this.meshes.length; i++) {
            var mesh = this.meshes[i]; //怎么判断是否要重新绑定
            var mat = mesh.material;
            var geo = mesh.geometry;
            //自定义着色器用自行处理uniform;
            if (mat["isShaderMaterial"]) {
                var customShader = mat["getShader"](this.renderer);
                var uniforms = customShader.uniforms;
                var cusUniforms = mat["uniforms"];
                if (curShader !== customShader) {
                    curShader = customShader;
                    this.renderer.bindShader(curShader, false);
                    //这两个默认得加上
                    if (uniforms["uViewMatrix"])
                        uniforms["uViewMatrix"] = this.camera.worldMatrixInverse.toArray();
                    if (uniforms["uProjectionMatrix"])
                        uniforms["uProjectionMatrix"] = this.camera.projectionMatrix.toArray();
                }
                //模型矩阵也默认加上
                if (uniforms["uModelMatrix"])
                    uniforms["uModelMatrix"] = mesh._worldMatrix.toArray();
                if (uniforms.uNormalMatrix) {
                    var modelViewMatrix_1 = tempMatrix4.multiplyMatrices(this.camera.worldMatrixInverse, mesh._worldMatrix);
                    var normalMatrix_1 = modelViewMatrix_1.invert().transpose();
                    // var normalMatrix = mesh._worldMatrix.invert().transpose();
                    uniforms["uNormalMatrix"] = normalMatrix_1.toArray();
                    // this.setShaderUniform(curShader, "uNormalMatrix", normalMatrix.toArray());
                }
                //处理所有自定义属性
                for (var u in cusUniforms) {
                    var uniform = cusUniforms[u];
                    var type = uniform.type;
                    var value = uniform.value;
                    switch (type) {
                        case UniformType.texture:
                            uniforms[u] = textureManager.bindTexture(value, undefined, false);
                            break;
                        case UniformType.color:
                            uniforms[u] = hex2rgb$1(value);
                            break;
                        case UniformType.matrix3:
                            uniforms[u] = value.toArray(true);
                            break;
                        case UniformType.vector2:
                        case UniformType.vector3:
                        case UniformType.vector4:
                        case UniformType.matrix4:
                            uniforms[u] = value.toArray();
                            break;
                        default:
                            uniforms[u] = value;
                            break;
                    }
                }
            }
            else {
                var maxBones = this.getMaxBones(mesh);
                var shader = getCusShader(this.renderer, mat, this.lightsConfig, mesh, maxBones, this.floatVertexTextures, this.fog, shadow);
                var uniforms = shader.uniforms;
                if (curShader !== shader) { //同一着色器只需要传一次相机参数和光照参数（因为都是场景全局）
                    curShader = shader;
                    //先绑定着色器，project不设置
                    this.renderer.bindShader(curShader, false);
                    //相机
                    uniforms["uViewMatrix"] = this.camera.worldMatrixInverse.toArray();
                    uniforms["uProjectionMatrix"] = this.camera.projectionMatrix.toArray();
                    //光照
                    if (mat._lightAffect) {
                        //只能给当前绑定的shader传值，否则location不存在
                        for (var j = 0; j < pointLightNum; j++) {
                            var key = "pointLights[" + j + "]";
                            uniforms[key].color = this.lightsConfig.pointLights[j].color;
                            uniforms[key].position = this.lightsConfig.pointLights[j].position;
                            uniforms[key].distance = this.lightsConfig.pointLights[j].distance;
                            uniforms[key].decay = this.lightsConfig.pointLights[j].decay;
                        }
                        for (var j = 0; j < dirLightNum; j++) {
                            var key = "directionalLights[" + j + "]", dl = this.lightsConfig.directionalLights[j];
                            uniforms[key].color = dl.color;
                            uniforms[key].direction = dl.direction;
                            uniforms[key].shadow = +dl.castShadow;
                            uniforms[key].shadowBias = dl.bias;
                            uniforms[key].shadowRadius = dl.radius;
                            uniforms[key].shadowMapSize = dl.mapSize;
                        }
                        uniforms.uAmbientLightColor = this.lightsConfig.ambientLightColor;
                        //暂时这么处理，只会一个灯光有影子
                        if (uniforms["uDirectionalShadowMatrix"]) {
                            uniforms["uDirectionalShadowMatrix"] = shadow.lightSpaceMatrix;
                            uniforms["uDirectionalShadowMap"] = textureManager.bindTexture(shadow.texture, undefined, false);
                        }
                    }
                }
                //是否带贴图，贴图考虑下图集，也就是texture的uv是否是01
                if (mat.map && mat.map.valid) {
                    var map = mat.map;
                    //找纹理，绑定纹理，多个纹理也是一样的方法
                    uniforms["uMap"] = textureManager.bindTexture(map, undefined, false);
                    //没加的加一个
                    if (!map.transform)
                        map.transform = new TextureMatrix(map);
                    //更新下
                    map.transform.update();
                    //赋值偏移
                    uniforms["uUvTransform"] = map.transform.mapCoord.toArray(true);
                    //对于透明像素有裁切的
                    var _a = map._uvs, x0 = _a.x0, y0 = _a.y0, x2 = _a.x2, y2 = _a.y2;
                    uniforms["uFrameUvs"] = [x0, y0, x2, y2];
                }
                //是否带环境贴图
                if (mat.envMap && mat.envMap.valid) { //环境贴图先不考虑图集的情况，一般一张大jpg
                    //找纹理，绑定纹理，多个纹理也是一样的方法
                    uniforms["uEnvMap"] = textureManager.bindTexture(mat.envMap, undefined, false);
                    //反射率
                    uniforms["uReflectivity"] = mat.reflectivity;
                    //传相机位置
                    uniforms["uCameraPosition"] = tempVec3.setFromMatrixPosition(this.camera._worldMatrix).toArray();
                }
                // @ts-ignore
                if (mat.normalMap && mat.normalMap.valid) { //环境贴图先不考虑图集的情况，一般一张大jpg
                    //找纹理，绑定纹理，多个纹理也是一样的方法
                    // @ts-ignore
                    uniforms["uNormalMap"] = textureManager.bindTexture(mat.normalMap, undefined, false);
                    // 传相机位置
                    uniforms["uCameraPosition"] = tempVec3.setFromMatrixPosition(this.camera._worldMatrix).toArray();
                }
                //uniform参数修改，好像目前就几个，且固定的，以后得仿three建数组
                uniforms["uMatColor"] = mat.colorArr;
                uniforms["uMatAlpha"] = mat.alpha;
                //带雾化的
                if (mat.useFog && this.fog) {
                    uniforms["uFogColor"] = this.fog.color;
                    // uniforms["uFogDensity"] = this.fog.density;
                    uniforms["uFogNear"] = this.fog.near;
                    uniforms["uFogFar"] = this.fog.far;
                }
                //mesh的模型矩阵
                uniforms["uModelMatrix"] = mesh._worldMatrix.toArray();
                //法线矩阵
                if (uniforms.uNormalMatrix) {
                    var modelViewMatrix = tempMatrix4.multiplyMatrices(this.camera.worldMatrixInverse, mesh._worldMatrix);
                    var normalMatrix = modelViewMatrix.invert().transpose();
                    // var normalMatrix = mesh._worldMatrix.invert().transpose();
                    uniforms["uNormalMatrix"] = normalMatrix.toArray();
                    // this.setShaderUniform(curShader, "uNormalMatrix", normalMatrix.toArray());
                }
                //骨骼需要的uniform
                if (mat.skinning && maxBones > 0) {
                    //@ts-ignore
                    var sMesh = mesh;
                    uniforms["uBindMatrix"] = sMesh.bindMatrix.toArray();
                    uniforms["uBindMatrixInverse"] = sMesh.bindMatrixInverse.toArray();
                    // sMesh.skeleton.update()
                    var skeleton = sMesh.skeleton;
                    if (skeleton) {
                        var bones = skeleton.bones;
                        if (this.floatVertexTextures) {
                            if (!skeleton.boneTexture) {
                                // layout (1 matrix = 4 pixels)
                                //      RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
                                //  with  8x8  pixel texture max   16 bones * 4 pixels =  (8 * 8)
                                //       16x16 pixel texture max   64 bones * 4 pixels = (16 * 16)
                                //       32x32 pixel texture max  256 bones * 4 pixels = (32 * 32)
                                //       64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64)
                                var size = Math.sqrt(bones.length * 4); // 4 pixels needed for 1 matrix
                                size = (function (value) {
                                    return Math.pow(2, Math.ceil(Math.log(value) / Math.LN2));
                                })(size);
                                size = Math.max(size, 4);
                                var boneMatrices = new Float32Array(size * size * 4); // 4 floats per RGBA pixel
                                boneMatrices.set(skeleton.boneMatrices); // copy current values
                                var boneTexture = new BaseTexture({ _data: boneMatrices, width: size, height: size });
                                boneTexture.mipmap = false;
                                boneTexture.scaleMode = SCALE_MODES.NEAREST;
                                boneTexture.premultipliedAlpha = false;
                                skeleton.boneMatrices = boneMatrices;
                                skeleton.boneTexture = boneTexture;
                                skeleton.boneTextureSize = size;
                            }
                            var location = textureManager.bindTexture(skeleton.boneTexture, undefined, false);
                            uniforms["uBoneTexture"] = location;
                            uniforms["uBoneTextureSize"] = skeleton.boneTextureSize;
                        }
                        else {
                            uniforms["uBoneMatrices"] = sMesh.skeleton.boneMatrices;
                        }
                    }
                }
            }
            //几何属性
            var glVaoBuffer = generateVaoBuffer(geo, this.renderer);
            //@ts-ignore
            var vao = glVaoBuffer.vaos[curShader._glShaderKey];
            var attrs = curShader.attributes;
            if (!vao) {
                //@ts-ignore vao添加各种attribute
                vao = glVaoBuffer.vaos[curShader._glShaderKey] = this.renderer.createVao()
                    //索引
                    // .addIndex(glVaoBuffer.indexBuffer)
                    //顶点
                    .addAttribute(glVaoBuffer.attrBuffer, attrs.aPosition, gl.FLOAT, false, geo._vertByteSize, 0 * 4);
                //颜色
                // .addAttribute(glVaoBuffer.attrBuffer, attrs.aColor, gl.FLOAT, true, geo._vertByteSize, 3 * 4)
                //uv
                // .addAttribute(glVaoBuffer.attrBuffer, attrs.aTextureCoord, gl.FLOAT, true, geo._vertByteSize, 6 * 4)
                //法线
                // .addAttribute(glVaoBuffer.attrBuffer, attrs.aNormal, gl.FLOAT, false, geo._vertByteSize, 8 * 4);
                //颜色不一定有
                if (attrs.aColor)
                    vao.addAttribute(glVaoBuffer.attrBuffer, attrs.aColor, gl.FLOAT, true, geo._vertByteSize, 3 * 4);
                //uv不一定有
                if (attrs.aTextureCoord)
                    vao.addAttribute(glVaoBuffer.attrBuffer, attrs.aTextureCoord, gl.FLOAT, true, geo._vertByteSize, 6 * 4);
                //法线不一定有
                if (attrs.aNormal)
                    vao.addAttribute(glVaoBuffer.attrBuffer, attrs.aNormal, gl.FLOAT, false, geo._vertByteSize, 8 * 4);
                //索引看情况加
                if (geo._indices)
                    vao.addIndex(glVaoBuffer.indexBuffer);
                //骨骼的
                if (attrs.aSkinWeight)
                    vao.addAttribute(glVaoBuffer.skinWeightBuffer, attrs.aSkinWeight, gl.FLOAT, false, 0, 0);
                if (attrs.aSkinIndex)
                    vao.addAttribute(glVaoBuffer.skinIndexBuffer, attrs.aSkinIndex, gl.UNSIGNED_BYTE, false, 0, 0);
                //变形数据，首次直接addAttribute
                var uploadBufferDatas;
                if (mesh.morphTargetInfluences && mat.morphTargets) {
                    uploadBufferDatas = addMorphtargetsAttr(mesh.morphTargetInfluences, geo, glVaoBuffer, vao, curShader, gl);
                }
                // 首次需要绑定buffer到vao，先绑定vao再绑定buffer和上传数据（upload里传false）,其实bindVao貌似已经绑定过了，再说吧
                this.renderer.bindVao(vao);
                //打包顶点、颜色、uv、法线到_attrBuffer.vertices
                packGeometry(geo);
                //所有数据绑定buffer，其实可以在上面构造GLBuffer里传数据，现在还是单独处理吧，这样判断比较多
                //需要分别绑定
                glVaoBuffer.attrBuffer.upload(geo._attrBuffer.vertices, 0, false); //首次还是bind吧，必须bind，否则buffer溢出
                //有索引才改
                if (geo._indices)
                    glVaoBuffer.indexBuffer.upload(geo._indices, 0, false); //首次还是bind吧
                //骨骼的
                if (attrs.aSkinWeight)
                    glVaoBuffer.skinWeightBuffer.upload(new Float32Array(geo._skinWeight), 0, false);
                if (attrs.aSkinIndex)
                    glVaoBuffer.skinIndexBuffer.upload(new Uint8Array(geo._skinIndex), 0, false);
                //还得在这里做数据的变形
                if (uploadBufferDatas)
                    uploadBufferDatas.forEach(function (e) {
                        e.buffer.upload(e.data, 0, false);
                    });
            }
            else {
                //变形数据，暂时只有这个要做改变，其他的估计到时也要搞，TODO
                var uploadBufferDatas;
                if (mesh.morphTargetInfluences && mat.morphTargets) {
                    uploadBufferDatas = addMorphtargetsAttr(mesh.morphTargetInfluences, geo, glVaoBuffer, vao, curShader, gl);
                }
                //进过上面判断，必有uploadBufferDatas，TODO,到时考虑不传force，用vao.dirty判断是否bind
                this.renderer.bindVao(vao, !!uploadBufferDatas);
                //判断是否需要重新上传数据,顶点，颜色，uv，法线
                if (packGeometry(geo))
                    glVaoBuffer.attrBuffer.upload(geo._attrBuffer.vertices, 0, false);
                //不修改，估计都不要变，需要修改时候TODO.好多数据，包括vao可能也需要重新bind
                // glVaoBuffer.attrBuffer.upload(glVaoBuffer._attrBuffer.vertices, 0, true)
                // glVaoBuffer.indexBuffer.upload(glVaoBuffer._indexBuffer, 0, true)
                //变形的数据可能传入的会改变，所以需要upload，还要重新修改数据，有removeAttribute的情况，TODO
                //还得在这里做数据的变形，不绑定
                if (uploadBufferDatas)
                    uploadBufferDatas.forEach(function (e) {
                        e.buffer.upload(e.data, 0, false /*true*/); //貌似里面有修改的Attribute队列，所以还是绑定下buffer
                    });
            }
            //根据材质切换渲染面，TODO，还有着色器也需要处理，法线以及光照正反面
            if (mat.side == RenderSideType.DoubleSide) {
                this.renderer.state.setCullFace(0); //不开启剔除
            }
            else {
                this.renderer.state.setCullFace(1);
                //设置剔除面
                this.renderer.state.setFrontFace(mat.side);
            }
            //绘制
            vao.draw(mat["isPointsMaterial"] ? gl.POINTS : mat.wireframe ? gl.LINES : gl.TRIANGLES);
        }
        this.meshes.length = 0;
    };
    D3Renderer.prototype.getMaxBones = function (object) {
        if (object.instanceType !== "SkinnedMesh3D")
            return 0;
        if (this.floatVertexTextures)
            return 1024;
        var skeleton = object.skeleton;
        var bones = skeleton.bones;
        var nVertexMatrices = Math.floor((this.maxVertexUniforms - 20) / 4);
        var maxBones = Math.min(nVertexMatrices, bones.length);
        if (maxBones < bones.length) {
            console.warn('Skeleton has ' + bones.length + ' bones. This GPU supports ' + maxBones + '.');
            return 0;
        }
        return maxBones;
    };
    return D3Renderer;
}(ObjectRenderer));
/**
 * 组转集合的所有属性到一个_attrBuffer
 * @param geo
 * @returns {boolean} 返回是否需要upload数据，一般是vao已有的情况下需要判断，新建vao时是必要upload的
 */
function packGeometry(geo) {
    //几何的字节长度
    var byteLength = geo._vertices.length / 3 * geo._vertByteSize;
    //不存在就建一个，要执行数据处理
    if (!geo._attrBuffer) {
        geo._attrBuffer = new BatchBuffer(byteLength);
    }
    //长度不一致了也需要，上面byteLength只计算顶点长度，其他，uv。normal啥的，直接给报错吧，要执行数据处理
    else if (geo._attrBuffer.vertices.byteLength !== byteLength) {
        //原来的销毁
        geo._attrBuffer.destroy();
        //新建一个
        geo._attrBuffer = new BatchBuffer(byteLength);
    }
    //数据也没有更新，直接return
    else if (!geo.attrBufferNeedUpdate) {
        return false; //表示没更新数据，一般这种情况只需要bindVao，而不需要再upload数据
    }
    var float32View = geo._attrBuffer.float32View;
    var count = 0;
    for (var j = 0; j < geo._vertices.length / 3; j++) {
        //顶点
        float32View[count++] = geo._vertices[j * 3];
        float32View[count++] = geo._vertices[j * 3 + 1];
        float32View[count++] = geo._vertices[j * 3 + 2];
        //@ts-ignore 颜色，以后搞成一位，现在有bug
        // geo._attrBuffer.uint32View[count++] = rgb2hex(geo._colors.slice(j * 3, j * 3 + 3)) + (1 * 255 << 24)
        float32View[count++] = geo._colors[j * 3];
        float32View[count++] = geo._colors[j * 3 + 1];
        float32View[count++] = geo._colors[j * 3 + 2];
        // float32View[count++] = 1;
        //uv
        float32View[count++] = geo._uvs[j * 2];
        float32View[count++] = geo._uvs[j * 2 + 1];
        //法线,可能不需要法线的情况，也加上先
        float32View[count++] = geo._normals[j * 3];
        float32View[count++] = geo._normals[j * 3 + 1];
        float32View[count++] = geo._normals[j * 3 + 2];
    }
    //标记下，数据不需要更新了
    geo.attrBufferNeedUpdate = false;
    //表示更新过数据
    return true; //不止要bindVao，还需要重新upload数据
}
//每个几何的权重缓存
var influencesList = {};
//每个几何的通道对应数据索引
var attrChannelHash = {};
//给uniform传值用
var morphInfluences = new Float32Array(8);
/**
 * 更新变形数据，考虑是否要变动attribute，只有
 * 返回要upload的数据
 * @param objectInfluences mesh上的权重数组
 * @param geo 几何
 * @param vao
 */
function addMorphtargetsAttr(objectInfluences, geo, glVaoBuffer, vao, shader, gl) {
    var morphTargets = geo._morphPositions;
    //这里的判断是有问题的，讲道理应该是mat.morphNormals&&geo._morphNormals;但是现在变形动画都由glb提供，里面只要有法线变形就会设置mat.morphNormals=true
    var morphNormals = geo._morphNormals;
    var length = objectInfluences.length; //权重数据总长度，基本不会被手动修改，到时排序只取权重大的，最多8
    //记录需要修改的数据
    var uploadBufferDatas = [];
    //原来几何上的权重，第一个元素标识数据索引，第二个元素标识值，第三个标识现在用的通道
    var influences = influencesList[geo.instanceId];
    //如果原先不存在
    if (!influences) {
        influences = [];
        for (var i = 0; i < length; i++) {
            influences[i] = [i, 0];
        }
        influencesList[geo.instanceId] = influences;
    }
    //通道对应的数据，确定哪些通道的数据要重新upload
    var attrChannel = attrChannelHash[geo.instanceId];
    if (!attrChannel) {
        attrChannel = []; //通道对应，数据索引
        attrChannel.length = 8;
        attrChannelHash[geo.instanceId] = attrChannel;
    }
    //vao上挂着有变形数据的移除，讲道理也是最多8
    for (var i = 0; i < 8 /*length*/; i++) {
        var influence = influences[i];
        if (influence && influence[1] !== 0) {
            if (morphTargets)
                vao.removeAttribute('morphTarget' + i);
            if (morphNormals && i < 4)
                vao.removeAttribute('morphNormal' + i);
        }
    }
    //重新处理变形数据，这个得排所有的
    for (var i = 0; i < length; i++) {
        var influence = influences[i];
        influence[0] = i;
        influence[1] = objectInfluences[i];
    }
    //按权重大小排序，大的优先
    influences.sort(absNumericalSort);
    var attrs = shader.attributes;
    //只取8个，不传着色器里计算并不会报错
    //有法线时只用4个，
    var attrLen = morphNormals ? 4 : 8;
    for (var i = 0; i < attrLen; i++) {
        var influence = influences[i];
        if (influence) {
            //索引
            var index = influence[0];
            var value = influence[1];
            if (value) {
                if (morphTargets && morphTargets[index]) {
                    //buffer没有就加
                    var targetBuffer = glVaoBuffer.morphTargetBuffers[index];
                    if (!targetBuffer) {
                        targetBuffer = glVaoBuffer.morphTargetBuffers[index] = GLBuffer.createVertexBuffer(gl, null, gl.STATIC_DRAW);
                    }
                    //记录需要修改传数据，通道值对应的buffer值不一致时，需要upload
                    if (attrChannel[i] !== index) {
                        attrChannel[i] = index;
                        uploadBufferDatas.push({
                            buffer: targetBuffer,
                            data: new Float32Array(morphTargets[index]) //data.vertices
                        });
                    }
                    vao.addAttribute(targetBuffer, attrs['morphTarget' + i], gl.FLOAT, false, 0, //3 * 4,
                    0 * 4, 'morphTarget' + i);
                }
                if (morphNormals && morphNormals[index]) { //法线只有4个
                    //buffer没有就加
                    var normalBuffer = glVaoBuffer.morphNormalBuffers[index];
                    if (!normalBuffer) {
                        normalBuffer = glVaoBuffer.morphNormalBuffers[index] = GLBuffer.createVertexBuffer(gl, null, gl.STATIC_DRAW);
                    }
                    //记录需要修改传数据，通道值对应的buffer值不一致时，需要upload，用后四个记录
                    if (attrChannel[i + 4] !== index) {
                        attrChannel[i + 4] = index;
                        uploadBufferDatas.push({
                            buffer: normalBuffer,
                            data: new Float32Array(morphNormals[index])
                        });
                    }
                    vao.addAttribute(glVaoBuffer.morphNormalBuffers[index], attrs['morphNormal' + i], gl.FLOAT, false, 0, // 3 * 4,
                    0 * 4, 'morphNormal' + i);
                }
                morphInfluences[i] = value;
                continue;
            }
        }
        morphInfluences[i] = 0;
    }
    //着色器修改
    shader.uniforms["morphTargetInfluences"] = morphInfluences;
    //需要修改数据的
    return uploadBufferDatas;
}
function absNumericalSort(a, b) {
    return Math.abs(b[1]) - Math.abs(a[1]);
}
WebglRenderer.registerPlugin('d3', D3Renderer);
var shadowMap;
//暂时只按照渲染器的id来缓存，到时可能还会有顶点或骨骼动画，再修改，TODO
var shadowShaders = {};
/**
 * 光源相机
 */
// let shadowCamera: OrthographicCamera;
/**
 * 光源空间矩阵
 */
// let shadowMatrix: Matrix4;
/**
 * 生成影子深度图
 * @param lights
 * @param meshes
 * @param renderer
 */
function getShadowMap(lights, meshes, renderer) {
    //找直线光，就一个，设置了castShadow的
    var dirLight = (function () {
        if (!lights || !lights.directionalLights || !lights.directionalLights.length)
            return null;
        for (var _i = 0, _a = lights.directionalLights; _i < _a.length; _i++) {
            var d = _a[_i];
            if (d.castShadow)
                return d;
        }
        return null;
    })();
    if (!dirLight)
        return null;
    var castMeshes = [], receiveMeshes = [];
    if (meshes && meshes.length) {
        for (var _i = 0, meshes_1 = meshes; _i < meshes_1.length; _i++) {
            var m = meshes_1[_i];
            //找设置了投影的物体，且是有光感材质的
            if (m.castShadow && m.material._lightAffect)
                castMeshes.push(m);
            //找设置了接收影子的物体
            if (m.receiveShadow && m.material._lightAffect)
                receiveMeshes.push(m);
        }
    }
    if (!castMeshes.length || !receiveMeshes.length)
        return null;
    var gl = renderer.gl;
    //建一个帧缓存
    shadowMap = shadowMap || new RenderTexture(new BaseRenderTexture(dirLight.mapSize[0], dirLight.mapSize[1]));
    //然后就可以根据直线光生成光照矩阵的深度贴图了
    //绑定帧缓存
    renderer.bindRenderTexture(shadowMap, null);
    //设置清除颜色
    renderer.clear([1, 1, 1, 1]);
    //设置不使用混色
    renderer.state.setBlend(false);
    //绑定着色器
    var shadowShader = shadowShaders[renderer.CONTEXT_UID] ||
        (shadowShaders[renderer.CONTEXT_UID] = new ShadowShader(renderer.gl));
    renderer.bindShader(shadowShader, false);
    //赋值uniform
    var uniforms = shadowShader.uniforms;
    // var position = dirLight.position, tPosition = dirLight.tPosition;
    // //计算光照空间矩阵
    // shadowCamera = shadowCamera || new OrthographicCamera(- 15, 15, 15, - 15, 1, 50);
    // shadowCamera.position.set(position[0], position[1], position[2]);
    // shadowCamera.lookAt(tPosition[0], tPosition[1], tPosition[2]);
    // shadowCamera.updateWorldMatrix();
    // shadowMatrix = shadowMatrix || new Matrix4;
    // shadowMatrix.set(
    //     0.5, 0.0, 0.0, 0.5,
    //     0.0, 0.5, 0.0, 0.5,
    //     0.0, 0.0, 0.5, 0.5,
    //     0.0, 0.0, 0.0, 1.0
    // );
    // shadowMatrix.multiply(shadowCamera.projectionMatrix);
    // shadowMatrix.multiply(shadowCamera.worldMatrixInverse);
    // uniforms["uLightSpaceMatrix"] = new Matrix4().multiply(shadowCamera.projectionMatrix).multiply(shadowCamera.worldMatrixInverse).toArray();
    //全在scene3d里计算了
    uniforms["uLightSpaceMatrix"] = dirLight.shadowMatrixDepth; //dirLight.shadowMatrix;
    //设置剔除
    renderer.state.setCullFace(1);
    //设置剔除面
    renderer.state.setFrontFace(1);
    castMeshes.forEach(function (m) {
        var geo = m.geometry, mat = m.material;
        uniforms["uModelMatrix"] = m._worldMatrix.toArray();
        // uniforms["uMatAlpha"] = mat.alpha;
        //几何属性
        var glVaoBuffer = generateVaoBuffer(geo, renderer);
        var vao = glVaoBuffer.vaos[renderer.CONTEXT_UID];
        var attrs = shadowShader.attributes;
        if (!vao) {
            //vao添加各种attribute
            vao = glVaoBuffer.vaos[renderer.CONTEXT_UID] = renderer.createVao()
                //顶点
                .addAttribute(glVaoBuffer.attrBuffer, attrs.aPosition, gl.FLOAT, false, geo._vertByteSize, 0 * 4);
            //索引看情况加
            if (geo._indices)
                vao.addIndex(glVaoBuffer.indexBuffer);
            //骨骼的以后再说TODO，如果带了法线，上面还要加上addAttribute(
            // if (attrs.aSkinWeight) vao.addAttribute(glVaoBuffer.skinWeightBuffer, attrs.aSkinWeight, gl.FLOAT, false, 0, 0);
            // if (attrs.aSkinIndex) vao.addAttribute(glVaoBuffer.skinIndexBuffer, attrs.aSkinIndex, gl.UNSIGNED_BYTE, false, 0, 0);
            //变形数据，首次直接addAttribute
            // var uploadBufferDatas: UploadBufferData[];
            // if (mesh.morphTargetInfluences && mat.morphTargets) {
            //     uploadBufferDatas = addMorphtargetsAttr(
            //         mesh.morphTargetInfluences,
            //         geo,
            //         glVaoBuffer,
            //         vao,
            //         curShader,
            //         gl
            //     )
            // }
            renderer.bindVao(vao);
            //打包顶点数据到vertices;不判断了，必要upload
            packGeometry(geo);
            //需要分别绑定
            glVaoBuffer.attrBuffer.upload(geo._attrBuffer.vertices, 0, false); //首次还是bind吧，必须bind，否则buffer溢出
            //有索引才改
            if (geo._indices)
                glVaoBuffer.indexBuffer.upload(geo._indices, 0, false); //首次还是bind吧
            //骨骼的
            // if (attrs.aSkinWeight) glVaoBuffer.skinWeightBuffer.upload(new Float32Array(geo._skinWeight), 0, false)
            // if (attrs.aSkinIndex) glVaoBuffer.skinIndexBuffer.upload(new Uint8Array(geo._skinIndex), 0, false)
            // //还得在这里做数据的变形
            // if (uploadBufferDatas) uploadBufferDatas.forEach((e) => {
            //     e.buffer.upload(e.data, 0, false);
            // })
        }
        else {
            //变形数据，暂时只有这个要做改变，其他的估计到时也要搞，TODO
            // var uploadBufferDatas: UploadBufferData[];
            // if (mesh.morphTargetInfluences && mat.morphTargets) {
            //     uploadBufferDatas = addMorphtargetsAttr(
            //         mesh.morphTargetInfluences,
            //         geo,
            //         glVaoBuffer,
            //         vao,
            //         curShader,
            //         gl
            //     )
            // }
            //进过上面判断，必有uploadBufferDatas，TODO,到时考虑不传force，用vao.dirty判断是否bind
            renderer.bindVao(vao /*, !!uploadBufferDatas*/);
            //判断是否需要重新上传数据
            if (packGeometry(geo))
                glVaoBuffer.attrBuffer.upload(geo._attrBuffer.vertices, 0, false);
            //不修改，估计都不要变，需要修改时候TODO.好多数据，包括vao可能也需要重新bind
            // glVaoBuffer.attrBuffer.upload(glVaoBuffer._attrBuffer.vertices, 0, true)
            // glVaoBuffer.indexBuffer.upload(glVaoBuffer._indexBuffer, 0, true)
            //变形的数据可能传入的会改变，所以需要upload，还要重新修改数据，有removeAttribute的情况，TODO
            //还得在这里做数据的变形，不绑定
            // if (uploadBufferDatas) uploadBufferDatas.forEach((e) => {
            //     e.buffer.upload(e.data, 0, false/*true*/);//貌似里面有修改的Attribute队列，所以还是绑定下buffer
            // })
        }
        //绘制
        // vao.draw(mat.wireframe ? gl.LINES : gl.TRIANGLES);
        vao.draw(mat["isPointsMaterial"] ? gl.POINTS : mat.wireframe ? gl.LINES : gl.TRIANGLES);
    });
    //纹理绑定回去
    renderer.bindRenderTexture(null, null);
    //混色设置回去
    renderer.state.setBlend(true);
    // renderer.state.setBlendMode(BLEND_MODES.NORMAL_NPM)//先不设置，让着色器里预乘
    //还有viewport还原回场景的，这部分放在flush吧
    return { texture: shadowMap, lightSpaceMatrix: dirLight.shadowMatrix, shadowType: null };
}
function generateVaoBuffer(geo, renderer) {
    var gl = renderer.gl;
    var glVaoBuffer = geo._glVaoBuffer[renderer.CONTEXT_UID];
    if (!glVaoBuffer) {
        glVaoBuffer = geo._glVaoBuffer[renderer.CONTEXT_UID] = {
            attrBuffer: GLBuffer.createVertexBuffer(gl, null, gl.STATIC_DRAW),
            vaos: {}
        };
        //有索引
        if (geo._indices)
            glVaoBuffer.indexBuffer = GLBuffer.createIndexBuffer(gl, null, gl.STATIC_DRAW);
        //TODO 有变形顶点，数据直接干进去，有性能问题再说 ，还是先不绑了，影响下面的vao
        if (geo._morphPositions) { //长度可以根据位置，还是根据，可能很多，用到时再建
            glVaoBuffer.morphTargetBuffers = []; //mesh.morphTargetInfluences.length
        }
        //有变形法线
        if (geo._morphNormals) {
            glVaoBuffer.morphNormalBuffers = [];
        }
        //骨骼
        if (geo._skinWeight)
            glVaoBuffer.skinWeightBuffer = GLBuffer.createVertexBuffer(gl, null, gl.STATIC_DRAW);
        if (geo._skinIndex)
            glVaoBuffer.skinIndexBuffer = GLBuffer.createVertexBuffer(gl, null, gl.STATIC_DRAW);
        //计算一次，打包所有的顶点属性，位置，颜色，uv，法线，感觉不合理，有修改也该执行
        // packGeometry(geo);//放外面自行处理了，反正这方法和上面的处理完全没关系
    }
    return glVaoBuffer;
}

/**
 * 判断是否是类型化数组
 * @param {*} object
 */
function isTypedArray(object) {
    return ArrayBuffer.isView(object) &&
        !(object instanceof DataView);
}
/**
 * 截取数组
 * @param array
 * @param from
 * @param to
 */
function arraySlice(array, from, to) {
    if (isTypedArray(array)) {
        // in ios9 array.subarray(from, undefined) will return empty array
        // but array.subarray(from) or array.subarray(from, len) is correct
        return new array.constructor(array.subarray(from, to !== undefined ? to : array.length));
    }
    return array.slice(from, to);
}
var InterpolateDiscrete = 2300;
var InterpolateLinear = 2301;
var InterpolateSmooth = 2302;

/**
 * 动画类型
 */
var AnimationType3D;
(function (AnimationType3D) {
    /**
     * 旋转
     */
    AnimationType3D["quaternion"] = "quaternion";
    /**
     * 缩放
     */
    AnimationType3D["scale"] = "scale";
    /**
     * 顶点权重
     */
    AnimationType3D["morphTargetInfluences"] = "morphTargetInfluences";
    /**
     * 位移
     */
    AnimationType3D["position"] = "position";
})(AnimationType3D || (AnimationType3D = {}));
/**
 * 记录动画的轨迹，实时计算，还是用每帧的，暂时按时间间隔来搞，实时计算吧
 * 统统用线性的吧，貌似时间都打过点
 */
var AnimationTrack3D = /** @class */ (function (_super) {
    __extends(AnimationTrack3D, _super);
    function AnimationTrack3D(
    /**
     * 需要改变属性的节点对象
     */
    node, 
    /**
     * 动画类型
     */
    animationType, 
    /**
     * 记录所有时间的数组，按顺序递增，没有的按最后一个时间的数据
     */
    times, 
    /**
     * 上述时间要对应的数值，values.length/times.length就是步长
     */
    values) {
        var _this = _super.call(this) || this;
        _this.node = node;
        _this.animationType = animationType;
        _this.times = times;
        _this.values = values;
        _this._instanceType = "AnimationTrack";
        //赋值函数，恢复录入时的初始状态
        // this.resetValue=()=>{
        switch (_this.animationType) {
            case AnimationType3D.position:
            case AnimationType3D.scale:
            case AnimationType3D.quaternion:
                var value_1 = _this.node[_this.animationType].clone().toArray();
                _this.resetValue = function () {
                    _this.node[_this.animationType].fromArray(value_1);
                };
                break;
            case AnimationType3D.morphTargetInfluences:
                if (_this.node.instanceType == "Mesh3D" || _this.node.instanceType == "SkinnedMesh3D") {
                    var value_2 = _this.node["morphTargetInfluences"] ? _this.node["morphTargetInfluences"].slice() : [];
                    _this.resetValue = function () {
                        var arr = _this.node["morphTargetInfluences"];
                        for (var i = 0; i < arr.length; i++) { //这里用morphTargetInfluences本身的长度
                            arr[i] = value_2[i] || 0;
                        }
                    };
                }
                break;
        }
        //给个空的
        if (!_this.resetValue)
            _this.resetValue = function () { };
        return _this;
    }
    /**
     * 传入时间设置对应的属性值，time大于所有动画总时间，外部处理
     * @param time
     */
    AnimationTrack3D.prototype.setValue = function (time) {
        var value = this.getValue(time);
        switch (this.animationType) {
            case AnimationType3D.position:
            case AnimationType3D.scale:
            case AnimationType3D.quaternion:
                this.node[this.animationType].fromArray(value);
                break;
            case AnimationType3D.morphTargetInfluences:
                if (this.node.instanceType == "Mesh3D" || this.node.instanceType == "SkinnedMesh3D") {
                    var arr = this.node["morphTargetInfluences"];
                    for (var i = 0; i < arr.length; i++) {
                        arr[i] = value[i] || 0;
                    }
                }
                break;
        }
    };
    AnimationTrack3D.prototype.getValue = function (time) {
        var size = this.getValueSize();
        //为0直接用第一帧数据
        if (time <= 0)
            return this.values.slice(0, size);
        //如果超过最后时间，给最后一帧数据
        if (time >= this.times[this.times.length - 1])
            return this.values.slice(-size);
        //取最近的两个时间索引，
        var t1 = this.findPreIndex(time);
        var t0 = t1 - 1;
        if (t0 < 0)
            return this.values.slice(0, size);
        //计算比例插值
        var scale = (time - this.times[t0]) / (this.times[t1] - this.times[t0]);
        //获取数组，
        var v0 = this.values.slice(t0 * size, t0 * size + size);
        var v1 = this.values.slice(t1 * size, t1 * size + size);
        // time = clamp(time, 0, this.times[this.times.length - 1]);
        //暂时都是线性的，到时再说
        if (this.animationType == AnimationType3D.quaternion) {
            return quaternionLinearInterpolate(scale, v0, v1);
        }
        return linearInterpolate(scale, v0, v1);
    };
    //每项尺寸
    AnimationTrack3D.prototype.getValueSize = function () {
        return this.values.length / this.times.length;
    };
    /**
     * 外部已经剔除了第一帧和最后一帧
     * @param time
     */
    AnimationTrack3D.prototype.findPreIndex = function (time) {
        var lastIndex = 0;
        for (var i = 0; i < this.times.length; i++) {
            if (this.times[i] > time) {
                lastIndex = i;
                break;
            }
        }
        return lastIndex;
    };
    AnimationTrack3D.prototype.destroy = function () {
        this.node = null;
        this.values = null;
        this.times = null;
    };
    return AnimationTrack3D;
}(HashObject));
//线性插值，除了四元数
function linearInterpolate(s, v0, v1) {
    var result = [];
    // values = this.sampleValues,
    // stride = this.valueSize,
    // offset1 = i1 * stride,
    // offset0 = offset1 - stride,
    // weight1 = (t - t0) / (t1 - t0),
    // weight0 = 1 - weight1;
    for (var i = 0; i !== v0.length; ++i) {
        // result[i] =
        //     values[offset0 + i] * weight0 +
        //     values[offset1 + i] * weight1;
        result[i] = v0[i] * (1 - s) + v1[i] * s;
    }
    return result;
}
function quaternionLinearInterpolate(s, v0, v1) {
    var result = [];
    Quaternion.slerpFlat(result, 0, v0, 0, v1, 0, s);
    return result;
}

var offsetMatrix = new Matrix4();
var identityMatrix = new Matrix4();
var Skeleton3D = /** @class */ (function (_super) {
    __extends(Skeleton3D, _super);
    function Skeleton3D(bones, boneInverses) {
        if (bones === void 0) { bones = []; }
        var _this = _super.call(this) || this;
        _this._instanceType = "Skeleton3D";
        _this.bones = bones.slice(0);
        _this.boneMatrices = new Float32Array(_this.bones.length * 16);
        if (!boneInverses) {
            _this.calculateInverses();
        }
        else {
            if (_this.bones.length === boneInverses.length) {
                _this.boneInverses = boneInverses.slice(0);
            }
            else {
                console.warn('boneInverses length error');
                _this.boneInverses = [];
                for (var i = 0, il = _this.bones.length; i < il; i++) {
                    _this.boneInverses.push(new Matrix4());
                }
            }
        }
        return _this;
    }
    Skeleton3D.prototype.calculateInverses = function () {
        this.boneInverses = [];
        for (var i = 0, il = this.bones.length; i < il; i++) {
            var inverse = new Matrix4();
            if (this.bones[i]) {
                inverse.setInverseOf(this.bones[i]._worldMatrix);
            }
            this.boneInverses.push(inverse);
        }
    };
    Skeleton3D.prototype.pose = function () {
        var bone, i, il;
        // recover the bind-time world matrices
        for (i = 0, il = this.bones.length; i < il; i++) {
            bone = this.bones[i];
            if (bone) {
                bone._worldMatrix.setInverseOf(this.boneInverses[i]);
            }
        }
        // compute the local matrices, positions, rotations and scales
        for (i = 0, il = this.bones.length; i < il; i++) {
            bone = this.bones[i];
            if (bone) {
                if (bone.parent && bone.parent.instanceType == "Bone3D") {
                    bone._localMatrix.setInverseOf(bone.parent._worldMatrix);
                    bone._localMatrix.multiply(bone._worldMatrix);
                }
                else {
                    bone._localMatrix.copy(bone._worldMatrix);
                }
                bone._localMatrix.decompose(bone.position, bone.quaternion, bone.scale);
            }
        }
    };
    /**
     * skinnedMesh3D里面调用
     */
    Skeleton3D.prototype.update = function () {
        // this.calculateInverses();
        var bones = this.bones;
        var boneInverses = this.boneInverses;
        var boneMatrices = this.boneMatrices;
        var boneTexture = this.boneTexture;
        // flatten bone matrices to array
        for (var i = 0, il = bones.length; i < il; i++) {
            // compute the offset between the current and the original transform
            var matrix = bones[i] ? bones[i]._worldMatrix : identityMatrix;
            offsetMatrix.multiplyMatrices(matrix, boneInverses[i]);
            //@ts-ignore
            offsetMatrix.toArray(boneMatrices, i * 16);
        }
        // if(this.instanceId==310)console.log(this.bones[0]._worldMatrix.elements[2])
        if (boneTexture)
            boneTexture.update();
    };
    Skeleton3D.prototype.clone = function () {
        return new Skeleton3D(this.bones, this.boneInverses);
    };
    Skeleton3D.prototype.getBoneByName = function (name) {
        for (var i = 0, il = this.bones.length; i < il; i++) {
            var bone = this.bones[i];
            if (bone.name === name)
                return bone;
        }
        return null;
    };
    Skeleton3D.prototype.destroy = function () {
        //TODO
    };
    return Skeleton3D;
}(HashObject));

/**
 * 记录骨骼数据用
 */
var Bone3D = /** @class */ (function (_super) {
    __extends(Bone3D, _super);
    function Bone3D() {
        var _this = _super.call(this) || this;
        _this._instanceType = 'Bone3D';
        return _this;
    }
    return Bone3D;
}(Object3D));

var SkinnedMesh3D = /** @class */ (function (_super) {
    __extends(SkinnedMesh3D, _super);
    function SkinnedMesh3D(geometry, material) {
        var _this = _super.call(this, geometry, material) || this;
        _this.bindMode = "attached";
        _this.bindMatrix = new Matrix4();
        _this.bindMatrixInverse = new Matrix4();
        _this._instanceType = "SkinnedMesh3D";
        var bones = _this.initBones();
        var skeleton = new Skeleton3D(bones);
        _this.bind(skeleton, _this._worldMatrix);
        _this.normalizeSkinWeights();
        return _this;
    }
    SkinnedMesh3D.prototype.initBones = function () {
        var bones = [], bone, gbone;
        var i, il;
        if (this.geometry && this.geometry.bones !== undefined) {
            // first, create array of 'Bone' objects from geometry data
            for (i = 0, il = this.geometry.bones.length; i < il; i++) {
                gbone = this.geometry.bones[i];
                // create new 'Bone' object
                bone = new Bone3D();
                bones.push(bone);
                // apply values
                bone.name = gbone.name;
                bone.position.fromArray(gbone.pos);
                bone.quaternion.fromArray(gbone.rotq);
                if (gbone.scl !== undefined)
                    bone.scale.fromArray(gbone.scl);
            }
            // second, create bone hierarchy
            for (i = 0, il = this.geometry.bones.length; i < il; i++) {
                gbone = this.geometry.bones[i];
                if ((gbone.par !== -1) && (gbone.par !== null) && (bones[gbone.par] !== undefined)) {
                    // subsequent bones in the hierarchy
                    bones[gbone.par].addChild(bones[i]);
                }
                else {
                    // topmost bone, immediate child of the skinned mesh
                    this.addChild(bones[i]);
                }
            }
        }
        // now the bones are part of the scene graph and children of the skinned mesh.
        // let's update the corresponding matrices
        this.updateWorldMatrix();
        return bones;
    };
    SkinnedMesh3D.prototype.bind = function (skeleton, bindMatrix) {
        this.skeleton = skeleton;
        if (bindMatrix === undefined) {
            this.updateWorldMatrix();
            this.skeleton.calculateInverses();
            bindMatrix = this._worldMatrix;
        }
        this.bindMatrix.copy(bindMatrix);
        this.bindMatrixInverse.setInverseOf(bindMatrix);
    };
    SkinnedMesh3D.prototype.pose = function () {
        this.skeleton.pose();
    };
    SkinnedMesh3D.prototype.normalizeSkinWeights = function () {
        var scale, i;
        if (this.geometry) {
            var vec = new Vector4();
            var skinWeight = this.geometry._skinWeight;
            var len = skinWeight.length / 4 || 0;
            for (i = 0; i < len; i++) {
                vec.x = skinWeight[i * 4];
                vec.y = skinWeight[i * 4 + 1];
                vec.z = skinWeight[i * 4 + 2];
                vec.w = skinWeight[i * 4 + 3];
                scale = 1.0 / vec.manhattanLength();
                if (scale !== Infinity) {
                    vec.multiplyScalar(scale);
                }
                else {
                    vec.set(1, 0, 0, 0); // do something reasonable
                }
                // skinWeight.setXYZW(i, vec.x, vec.y, vec.z, vec.w);
                skinWeight[i * 4] = vec.x;
                skinWeight[i * 4 + 1] = vec.y;
                skinWeight[i * 4 + 2] = vec.z;
                skinWeight[i * 4 + 3] = vec.w;
            }
        }
    };
    SkinnedMesh3D.prototype.updateWorldMatrix = function () {
        _super.prototype.updateWorldMatrix.call(this);
        if (this.bindMode === 'attached') {
            this.bindMatrixInverse.setInverseOf(this._worldMatrix);
        }
        else if (this.bindMode === 'detached') {
            this.bindMatrixInverse.setInverseOf(this.bindMatrix);
        }
        else ;
    };
    SkinnedMesh3D.prototype.update = function () {
        if (!this.visible)
            return;
        this.skeleton.update();
        _super.prototype.update.call(this);
    };
    SkinnedMesh3D.prototype.clone = function () {
        return new SkinnedMesh3D(this.geometry, this.material).copy(this);
    };
    return SkinnedMesh3D;
}(Mesh3D));
//暂时只有这里用到，就几个方法，简单写
var Vector4 = /** @class */ (function () {
    function Vector4(x, y, z, w) {
        if (x === void 0) { x = 0; }
        if (y === void 0) { y = 0; }
        if (z === void 0) { z = 0; }
        if (w === void 0) { w = 1; }
        this.x = x;
        this.y = y;
        this.z = z;
        this.w = w;
    }
    Vector4.prototype.set = function (x, y, z, w) {
        this.x = x;
        this.y = y;
        this.z = z;
        this.w = w;
        return this;
    };
    Vector4.prototype.multiplyScalar = function (scalar) {
        this.x *= scalar;
        this.y *= scalar;
        this.z *= scalar;
        this.w *= scalar;
        return this;
    };
    Vector4.prototype.manhattanLength = function () {
        return Math.abs(this.x) + Math.abs(this.y) + Math.abs(this.z) + Math.abs(this.w);
    };
    return Vector4;
}());

/**
 * 用于管理传入的AnimationClips，为了多clips动画的切换
 * 不需要加入到舞台中
 * 自行加入到循环里，执行update
 * 暂时不允许多状态存在
 */
var AnimationManager = /** @class */ (function (_super) {
    __extends(AnimationManager, _super);
    /**
     * 传入
     * @param animationClips 所有的clip
     */
    function AnimationManager(animationClips) {
        var _this = _super.call(this) || this;
        _this.animationClips = animationClips;
        _this._instanceType = "AnimationManager";
        //所有的都停下先
        _this.stop();
        return _this;
    }
    /**
     * 获取一个AnimationClip，比如想自己控制
     * @param name
     */
    AnimationManager.prototype.getAniClipByName = function (name) {
        for (var i = 0; i < this.animationClips.length; i++) {
            if (this.animationClips[i].name == name)
                return this.animationClips[i];
        }
        return null;
    };
    /**
     * 切换动画，会停止当前播放的动画
     * 精细播放自己获取并控制，这个方法只针对多clip切换
     * @param name
     * @param loops 循环次数，0表示无限循环，默认0
     */
    AnimationManager.prototype.showAni = function (name, loops, callback) {
        if (loops === void 0) { loops = 0; }
        var clip = this.getAniClipByName(name);
        if (!clip)
            return null;
        //因为正在播放的动画会影响其他动画的初始状态，必须先重置
        if (this.currentClip)
            this.currentClip.resetState();
        this.currentClip = clip;
        //播放
        clip.startAniRange(0, undefined, loops, callback);
        //返回一个，可以自己玩
        return clip;
    };
    /**
     * 停止
     */
    AnimationManager.prototype.stop = function () {
        this.animationClips.forEach(function (a) { a.stop(); });
        this.currentClip = null;
    };
    /**
     * 重置并停止
     */
    AnimationManager.prototype.reset = function () {
        this.animationClips.forEach(function (a) { a.resetState(); });
        this.currentClip = null;
    };
    /**
     * 循环更新方法
     * @param deltaTime 按秒计，默认0.0167
     */
    AnimationManager.prototype.update = function (deltaTime) {
        if (deltaTime === void 0) { deltaTime = 0.0167; }
        for (var i = 0; i < this.animationClips.length; i++) {
            this.animationClips[i].update(deltaTime);
        }
    };
    AnimationManager.prototype.destroy = function () {
        this.animationClips = null;
        this.currentClip = null;
    };
    return AnimationManager;
}(HashObject));

//暂时只有gltf里会用到。如果还有其他地方用到，放到utils里
var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
/**
 * 解码
 * @param input
 * @param utf8Decode
 * @returns
 */
function atob_base64Decode(input, utf8Decode) {
    if (utf8Decode === void 0) { utf8Decode = false; }
    var output = "";
    var chr1, chr2, chr3;
    var enc1, enc2, enc3, enc4;
    var i = 0;
    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
    while (i < input.length) {
        enc1 = _keyStr.indexOf(input.charAt(i++));
        enc2 = _keyStr.indexOf(input.charAt(i++));
        enc3 = _keyStr.indexOf(input.charAt(i++));
        enc4 = _keyStr.indexOf(input.charAt(i++));
        chr1 = (enc1 << 2) | (enc2 >> 4);
        chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
        chr3 = ((enc3 & 3) << 6) | enc4;
        output = output + String.fromCharCode(chr1);
        if (enc3 != 64) {
            output = output + String.fromCharCode(chr2);
        }
        if (enc4 != 64) {
            output = output + String.fromCharCode(chr3);
        }
    }
    if (utf8Decode)
        output = _utf8_decode(output); //加了会出问题,TODO
    return output;
}
// private method for UTF-8 decoding  
function _utf8_decode(utftext) {
    var string = "";
    var i = 0;
    var c = 0;
    var c2 = 0;
    var c3 = 0;
    while (i < utftext.length) {
        c = utftext.charCodeAt(i);
        if (c < 128) {
            string += String.fromCharCode(c);
            i++;
        }
        else if ((c > 191) && (c < 224)) {
            c2 = utftext.charCodeAt(i + 1);
            string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
            i += 2;
        }
        else {
            c2 = utftext.charCodeAt(i + 1);
            c3 = utftext.charCodeAt(i + 2);
            string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
            i += 3;
        }
    }
    return string;
}
////////////////////////下面的是jquery，2012年的代码
// var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
//     a256 = '',
//     r64 = [256],
//     r256 = [256],
//     i = 0;
// var UTF8 = {
//     /**
//      * Encode multi-byte Unicode string into utf-8 multiple single-byte characters
//      * (BMP / basic multilingual plane only)
//      *
//      * Chars in range U+0080 - U+07FF are encoded in 2 chars, U+0800 - U+FFFF in 3 chars
//      *
//      * @param {String} strUni Unicode string to be encoded as UTF-8
//      * @returns {String} encoded string
//      */
//     encode: function (strUni) {
//         // use regular expressions & String.replace callback function for better efficiency
//         // than procedural approaches
//         var strUtf = strUni.replace(/[\u0080-\u07ff]/g, // U+0080 - U+07FF => 2 bytes 110yyyyy, 10zzzzzz
//             function (c) {
//                 var cc = c.charCodeAt(0);
//                 return String.fromCharCode(0xc0 | cc >> 6, 0x80 | cc & 0x3f);
//             })
//             .replace(/[\u0800-\uffff]/g, // U+0800 - U+FFFF => 3 bytes 1110xxxx, 10yyyyyy, 10zzzzzz
//                 function (c) {
//                     var cc = c.charCodeAt(0);
//                     return String.fromCharCode(0xe0 | cc >> 12, 0x80 | cc >> 6 & 0x3F, 0x80 | cc & 0x3f);
//                 });
//         return strUtf;
//     },
//     /**
//      * Decode utf-8 encoded string back into multi-byte Unicode characters
//      *
//      * @param {String} strUtf UTF-8 string to be decoded back to Unicode
//      * @returns {String} decoded string
//      */
//     decode: function (strUtf) {
//         // note: decode 3-byte chars first as decoded 2-byte strings could appear to be 3-byte char!
//         var strUni = strUtf.replace(/[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g, // 3-byte chars
//             function (c) { // (note parentheses for precence)
//                 var cc = ((c.charCodeAt(0) & 0x0f) << 12) | ((c.charCodeAt(1) & 0x3f) << 6) | (c.charCodeAt(2) & 0x3f);
//                 return String.fromCharCode(cc);
//             })
//             .replace(/[\u00c0-\u00df][\u0080-\u00bf]/g, // 2-byte chars
//                 function (c) { // (note parentheses for precence)
//                     var cc = (c.charCodeAt(0) & 0x1f) << 6 | c.charCodeAt(1) & 0x3f;
//                     return String.fromCharCode(cc);
//                 });
//         return strUni;
//     }
// };
// while (i < 256) {
//     var c = String.fromCharCode(i);
//     a256 += c;
//     r256[i] = i;
//     r64[i] = b64.indexOf(c);
//     ++i;
// }
// function code(s, discard, alpha, beta, w1, w2) {
//     s = String(s);
//     var buffer = 0,
//         i = 0,
//         length = s.length,
//         result = '',
//         bitsInBuffer = 0;
//     while (i < length) {
//         var c = s.charCodeAt(i);
//         c = c < 256 ? alpha[c] : -1;
//         buffer = (buffer << w1) + c;
//         bitsInBuffer += w1;
//         while (bitsInBuffer >= w2) {
//             bitsInBuffer -= w2;
//             var tmp = buffer >> bitsInBuffer;
//             result += beta.charAt(tmp);
//             buffer ^= tmp << bitsInBuffer;
//         }
//         ++i;
//     }
//     if (!discard && bitsInBuffer > 0) result += beta.charAt(buffer << (w2 - bitsInBuffer));
//     return result;
// }
// // var Plugin = function (dir, input, encode) {
// //     return input ? Plugin[dir](input, encode) : dir ? null : this;
// // };
// // Plugin["btoa"] = Plugin["encode"] = function (plain, utf8encode) {
// //     plain = Plugin["raw"] === false || Plugin["utf8encode"] || utf8encode ? UTF8.encode(plain) : plain;
// //     plain = code(plain, false, r256, b64, 8, 6);
// //     return plain + '===='.slice((plain.length % 4) || 4);
// // };
// // Plugin["atob"] = Plugin["decode"] = function (coded, utf8decode) {
// //     coded = coded.replace(/[^A-Za-z0-9\+\/\=]/g, "");
// //     coded = String(coded).split('=');
// //     var i = coded.length;
// //     do {
// //         --i;
// //         coded[i] = code(coded[i], true, r64, a256, 6, 8);
// //     } while (i > 0);
// //     coded = coded.join('');
// //     return Plugin["raw"] === false || Plugin["utf8decode"] || utf8decode ? UTF8.decode(coded) : coded;
// // };
// //base64编码
// export function btoa_base64Encode(plain, utf8encode = false) {
//     if (utf8encode) plain = UTF8.encode(plain);
//     plain = code(plain, false, r256, b64, 8, 6);
//     return plain + '===='.slice((plain.length % 4) || 4);
// };
// //base64解码
// export function atob_base64Decode(coded, utf8decode = false) {
//     coded = coded.replace(/[^A-Za-z0-9\+\/\=]/g, "");
//     coded = String(coded).split('=');
//     var i = coded.length;
//     do {
//         --i;
//         coded[i] = code(coded[i], true, r64, a256, 6, 8);
//     } while (i > 0);
//     coded = coded.join('');
//     return utf8decode ? UTF8.decode(coded) : coded;
// };

var BINARY_EXTENSION_HEADER_MAGIC = 'glTF'; //这个用到了
var BINARY_EXTENSION_HEADER_LENGTH = 12;
var BINARY_EXTENSION_CHUNK_TYPES = { JSON: 0x4E4F534A, BIN: 0x004E4942 };
/*********************************/
/********** EXTENSIONS ***********/
/*********************************/
var EXTENSIONS = {
    KHR_BINARY_GLTF: 'KHR_binary_glTF',
    KHR_DRACO_MESH_COMPRESSION: 'KHR_draco_mesh_compression',
    KHR_LIGHTS_PUNCTUAL: 'KHR_lights_punctual',
    KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness',
    KHR_MATERIALS_UNLIT: 'KHR_materials_unlit',
    MSFT_TEXTURE_DDS: 'MSFT_texture_dds'
};
/*********************************/
/********** INTERNALS ************/
/*********************************/
/* CONSTANTS */
var WEBGL_CONSTANTS = {
    FLOAT: 5126,
    //FLOAT_MAT2: 35674,
    FLOAT_MAT3: 35675,
    FLOAT_MAT4: 35676,
    FLOAT_VEC2: 35664,
    FLOAT_VEC3: 35665,
    FLOAT_VEC4: 35666,
    LINEAR: 9729,
    REPEAT: 10497,
    SAMPLER_2D: 35678,
    POINTS: 0,
    LINES: 1,
    LINE_LOOP: 2,
    LINE_STRIP: 3,
    TRIANGLES: 4,
    TRIANGLE_STRIP: 5,
    TRIANGLE_FAN: 6,
    UNSIGNED_BYTE: 5121,
    UNSIGNED_SHORT: 5123
};
var WEBGL_COMPONENT_TYPES = {
    5120: Int8Array,
    5121: Uint8Array,
    5122: Int16Array,
    5123: Uint16Array,
    5125: Uint32Array,
    5126: Float32Array
};
var WEBGL_TYPE_SIZES = {
    'SCALAR': 1,
    'VEC2': 2,
    'VEC3': 3,
    'VEC4': 4,
    'MAT2': 4,
    'MAT3': 9,
    'MAT4': 16
};
/**
 * 变形枚举
 */
var PATH_PROPERTIES = {
    scale: 'scale',
    translation: 'position',
    rotation: 'quaternion',
    weights: 'morphTargetInfluences',
    position: "position"
};
/**
 * 补间类型，暂时只有线性的InterpolateLinear
 */
var INTERPOLATION = {
    CUBICSPLINE: InterpolateSmooth,
    // KeyframeTrack.optimize() can't handle glTF Cubic Spline output values layout,
    // using THREE.InterpolateSmooth for KeyframeTrack instantiation to prevent optimization.
    // See KeyframeTrack.optimize() for the detail.
    LINEAR: InterpolateLinear,
    STEP: InterpolateDiscrete
};
/**
 * 直接拿数据解析
 * @param json 对象数据，可以是序列化的字符串，不能是二进制数据
 * @param onLoad
 * @param onError
 * @param extensions 内部调用传，外部使用不需要
 */
function parseGltf(json, onLoad, onError, extensions) {
    //如果是字符串
    if (typeof json === 'string')
        json = JSON.parse(json);
    //
    var parser = new GLTFParser(json, extensions);
    parser.parse(function (scene, scenes, cameras, animations, json) {
        var obj = {
            scene: scene,
            scenes: scenes,
            cameras: cameras,
            animations: animations,
            asset: json.asset,
            parser: parser,
        };
        //有动画，创建一个管理器
        if (animations && animations.length)
            obj.animationManager = new AnimationManager(animations);
        onLoad(obj);
    }, onError);
}
/**
 * 直接按函数导出，不用类，
 * TODO 后续是否考虑优化，gltf格式其实不需要用二进制解析，再说吧，就怕后缀能修改，
 * @param url
 * @param onLoad
 * @param onError
 */
function loadGltf(url, onLoad, onError) {
    var callback = function (s, res) {
        if (s) { //得到二进制数据
            try {
                var content;
                var extensions = {};
                if (typeof res === 'string') { //其实加载到的肯定是二进制对象
                    content = res;
                }
                else {
                    //glb文件加载到的magic=glTF，而gltf文件加载到的就是普通的字符串转的二进制数据
                    var magic = decodeText(new Uint8Array(res, 0, 4));
                    if (magic === BINARY_EXTENSION_HEADER_MAGIC) {
                        try {
                            extensions[EXTENSIONS.KHR_BINARY_GLTF] = new GLTFBinaryExtension(res);
                        }
                        catch (error) {
                            if (onError)
                                onError(error);
                            return;
                        }
                        content = extensions[EXTENSIONS.KHR_BINARY_GLTF].content;
                    }
                    else {
                        content = decodeText(new Uint8Array(res));
                    }
                }
                var json = JSON.parse(content);
                // console.log(json)
                if (json.asset === undefined || json.asset.version[0] < 2) {
                    onError && onError("version error");
                    return;
                }
                parseGltf(json, onLoad, onError, extensions);
                // var parser = new GLTFParser(json, extensions);
                // parser.parse(function (scene, scenes, cameras, animations, json) {
                // 	const obj: any = {
                // 		scene,
                // 		scenes,
                // 		cameras,
                // 		animations,
                // 		asset: json.asset,
                // 		parser,
                // 		// userData: {}
                // 	}
                // 	//有动画，创建一个管理器
                // 	if (animations && animations.length) obj.animationManager = new AnimationManager(animations);
                // 	onLoad(obj)
                // }, onError);
            }
            catch (e) {
                onError && onError(e);
            }
        }
        else {
            onError && onError(res);
        }
    };
    GlobalLoader.loadAB(callback, url);
}
/**
 * 去掉了除mesh和node以外的所有东西（骨骼，线等都没有）
 * 动画需要烘焙打点
 */
// export class GLTFLoader extends EventDispatcher {
// 	constructor() {//anonymous
// 		super();
// 	}
// 	load(
// 		url: string,
// 		onLoad: (gltf) => void,
// 		onError: (err: any) => void
// 	) {
// 		var scope = this;
// 		let callback = (s: boolean, res: any) => {
// 			if (s) {//得到二进制数据
// 				try {
// 					scope.parse(res, function (gltf) {
// 						onLoad(gltf);
// 					}, onError);
// 				} catch (e) {
// 					onError(e);
// 				}
// 			} else {
// 				onError && onError(res)
// 			}
// 		}
//      GlobalLoader.loadAB(callback, url);
// 	}
// 	parse(data: any, onLoad: (res: any) => void, onError: (err: any) => void) {
// 		var content: string;
// 		var extensions = {};
// 		if (typeof data === 'string') {
// 			content = data;
// 		} else {
// 			var magic = decodeText(new Uint8Array(data, 0, 4));
// 			if (magic === BINARY_EXTENSION_HEADER_MAGIC) {
// 				try {
// 					extensions[EXTENSIONS.KHR_BINARY_GLTF] = new GLTFBinaryExtension(data);
// 				} catch (error) {
// 					if (onError) onError(error);
// 					return;
// 				}
// 				content = extensions[EXTENSIONS.KHR_BINARY_GLTF].content;
// 			} else {
// 				content = decodeText(new Uint8Array(data));
// 			}
// 		}
// 		var json = JSON.parse(content);
// 		// console.log(json)
// 		if (json.asset === undefined || json.asset.version[0] < 2) {
// 			onError && onError("版本格式有问题")
// 			return;
// 		}
// 		var parser = new GLTFParser(json, extensions);
// 		parser.parse(function (scene, scenes, cameras, animations, json) {
// 			var glTF = {
// 				scene,
// 				scenes,
// 				cameras,
// 				animations,
// 				asset: json.asset,
// 				parser,
// 				userData: {}
// 			};
// 			// addUnknownExtensionsToUserData(extensions, glTF, json);
// 			// console.log(22222)
// 			onLoad(glTF);
// 		}, onError);
// 	}
// }
/**
 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#default-material
 */
function createDefaultMaterial() {
    // return new THREE.MeshStandardMaterial({
    // 	color: 0xFFFFFF,
    // 	emissive: 0x000000,
    // 	metalness: 1,
    // 	roughness: 1,
    // 	transparent: false,
    // 	depthTest: true,
    // 	side: THREE.FrontSide
    // });
    return new LightMaterial({
        color: 0xFFFFFF,
        side: 0
    });
}
/**
 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#morph-targets
 *
 * @param {Geometry} geometry
 * @param {Array<GLTF.Target>} targets
 * @param {Array<BufferAttribute>} accessors
 */
function addMorphTargets(geometry, targets, accessors) {
    var hasMorphPosition = false;
    var hasMorphNormal = false;
    for (var i = 0, il = targets.length; i < il; i++) {
        var target = targets[i];
        if (target.POSITION !== undefined)
            hasMorphPosition = true;
        if (target.NORMAL !== undefined)
            hasMorphNormal = true;
        if (hasMorphPosition && hasMorphNormal)
            break;
    }
    if (!hasMorphPosition && !hasMorphNormal)
        return;
    var morphPositions = [];
    var morphNormals = [];
    for (var i = 0, il = targets.length; i < il; i++) {
        var target = targets[i];
        var attributeName = 'morphTarget' + i;
        if (hasMorphPosition) {
            // Three.js morph position is absolute value. The formula is
            //   basePosition
            //     + weight0 * ( morphPosition0 - basePosition )
            //     + weight1 * ( morphPosition1 - basePosition )
            //     ...
            // while the glTF one is relative
            //   basePosition
            //     + weight0 * glTFmorphPosition0
            //     + weight1 * glTFmorphPosition1
            //     ...
            // then we need to convert from relative to absolute here.
            var mPostions = void 0;
            if (target.POSITION !== undefined) {
                mPostions = [];
                // Cloning not to pollute original accessor
                var positionAttribute = cloneBufferAttribute(accessors[target.POSITION]);
                positionAttribute.name = attributeName;
                var position = geometry._vertices;
                for (var j = 0, jl = positionAttribute.count; j < jl; j++) {
                    // positionAttribute.setXYZ(
                    // 	j,
                    // 	positionAttribute.getX(j) + position.getX(j),
                    // 	positionAttribute.getY(j) + position.getY(j),
                    // 	positionAttribute.getZ(j) + position.getZ(j)
                    // );
                    mPostions.push(positionAttribute.getX(j) + position[j * 3], positionAttribute.getY(j) + position[j * 3 + 1], positionAttribute.getZ(j) + position[j * 3 + 2]);
                }
            }
            else {
                //用同一个数组吧，一个修改都改
                mPostions = geometry._vertices;
            }
            morphPositions.push(mPostions);
        }
        if (hasMorphNormal) {
            // see target.POSITION's comment
            var mNormals = void 0;
            // var normalAttribute;
            if (target.NORMAL !== undefined) {
                mNormals = [];
                var normalAttribute = cloneBufferAttribute(accessors[target.NORMAL]);
                normalAttribute.name = attributeName;
                // var normal = geometry.attributes.normal;
                var normal = geometry._normals;
                for (var j = 0, jl = normalAttribute.count; j < jl; j++) {
                    // normalAttribute.setXYZ(
                    // 	j,
                    // 	normalAttribute.getX(j) + normal.getX(j),
                    // 	normalAttribute.getY(j) + normal.getY(j),
                    // 	normalAttribute.getZ(j) + normal.getZ(j)
                    // );
                    mNormals.push(normalAttribute.getX(j) + normal[j * 3], normalAttribute.getY(j) + normal[j * 3 + 1], normalAttribute.getZ(j) + normal[j * 3 + 2]);
                }
            }
            else {
                mNormals = geometry._normals;
            }
            morphNormals.push(mNormals);
        }
    }
    //morphPositions是个positionAttribute的数组，我那边应该只需要数据，步长啥的都自己干
    if (hasMorphPosition)
        geometry._morphPositions = morphPositions;
    if (hasMorphNormal)
        geometry._morphNormals = morphNormals;
}
function cloneBufferAttribute(attribute) {
    if (attribute.isInterleavedBufferAttribute) {
        var count = attribute.count;
        var itemSize = attribute.itemSize;
        var array = attribute.array.slice(0, count * itemSize);
        for (var i = 0; i < count; ++i) {
            array[i * itemSize] = attribute.getX(i);
            if (itemSize >= 2)
                array[i * itemSize + 1] = attribute.getY(i);
            if (itemSize >= 3)
                array[i * itemSize + 2] = attribute.getZ(i);
            if (itemSize >= 4)
                array[i * itemSize + 3] = attribute.getW(i);
        }
        return new BufferAttribute(array, itemSize, attribute.normalized);
    }
    return attribute.clone();
}
/**
 * @param {Mesh3D} mesh
 * @param {GLTF.Mesh} meshDef
 */
function updateMorphTargets(mesh, meshDef) {
    mesh.updateMorphTargets();
    if (meshDef.weights !== undefined) {
        for (var i = 0, il = meshDef.weights.length; i < il; i++) {
            mesh.morphTargetInfluences[i] = meshDef.weights[i];
        }
    }
    // .extras has user-defined data, so check that .extras.targetNames is an array.
    if (meshDef.extras && Array.isArray(meshDef.extras.targetNames)) {
        var targetNames = meshDef.extras.targetNames;
        if (mesh.morphTargetInfluences.length === targetNames.length) {
            mesh.morphTargetDictionary = {};
            for (var i = 0, il = targetNames.length; i < il; i++) {
                mesh.morphTargetDictionary[targetNames[i]] = i;
            }
        }
        else {
            console.warn('GLTFLoader: Invalid extras.targetNames length. Ignoring names.');
        }
    }
}
function isPrimitiveEqual(a, b) {
    if (a.indices !== b.indices) {
        return false;
    }
    return isObjectEqual(a.attributes, b.attributes);
}
function isObjectEqual(a, b) {
    if (Object.keys(a).length !== Object.keys(b).length)
        return false;
    for (var key in a) {
        if (a[key] !== b[key])
            return false;
    }
    return true;
}
function getCachedGeometry(cache, newPrimitive) {
    for (var i = 0, il = cache.length; i < il; i++) {
        var cached = cache[i];
        if (isPrimitiveEqual(cached.primitive, newPrimitive))
            return cached.promise;
    }
    return null;
}
var GLTFParser = /** @class */ (function () {
    function GLTFParser(json, extensions, options) {
        //下面两个加载器暂时不需要
        // this.textureLoader = new THREE.TextureLoader(this.options.manager);
        // this.textureLoader.setCrossOrigin(this.options.crossOrigin);
        if (json === void 0) { json = {}; }
        if (extensions === void 0) { extensions = {}; }
        if (options === void 0) { options = {}; }
        this.json = json;
        this.extensions = extensions;
        this.options = options;
        //缓存
        this.cache = new GLTFRegistry();
        // BufferGeometry caching
        this.primitiveCache = [];
        this.multiplePrimitivesCache = [];
        this.multiPassGeometryCache = [];
        /**
         * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#scenes
         * @param {number} sceneIndex
         * @return {Promise<Scene3D>}
         */
        this.loadScene = function () {
            // scene node hierachy builder
            function buildNodeHierachy(nodeId, parentObject, json, allNodes, skins) {
                var node = allNodes[nodeId];
                var nodeDef = json.nodes[nodeId];
                // build skeleton here as well
                //骨骼以后再说
                if (nodeDef.skin !== undefined) { //暂时应该没有骨骼
                    // var meshes = node.isGroup === true ? node.children : [node];
                    var meshes = node.instanceType == "Object3D" ? node.children : [node];
                    for (var i = 0; i < meshes.length; i++) {
                        var mesh = meshes[i];
                        var skinEntry = skins[nodeDef.skin];
                        var bones = [];
                        var boneInverses = [];
                        for (var j = 0, jl = skinEntry.joints.length; j < jl; j++) {
                            var jointId = skinEntry.joints[j];
                            var jointNode = allNodes[jointId];
                            if (jointNode) {
                                bones.push(jointNode);
                                var mat = new Matrix4();
                                if (skinEntry.inverseBindMatrices !== undefined) {
                                    mat.fromArray(skinEntry.inverseBindMatrices.array, j * 16);
                                }
                                boneInverses.push(mat);
                            }
                            else {
                                console.warn('Joint "%s" could not be found.', jointId);
                            }
                        }
                        mesh.bind(new Skeleton3D(bones, boneInverses), mesh._worldMatrix);
                    }
                }
                // build node hierachy
                parentObject.addChild(node);
                if (nodeDef.children) {
                    var children = nodeDef.children;
                    for (var i = 0; i < children.length; i++) {
                        var child = children[i];
                        //临时处理，骨骼有问题，
                        if (node)
                            buildNodeHierachy(child, node, json, allNodes, skins);
                    }
                }
            }
            return function loadScene(sceneIndex) {
                var json = this.json;
                this.extensions;
                var sceneDef = this.json.scenes[sceneIndex];
                return this.getMultiDependencies([
                    'node',
                    'skin'
                ]).then(function (dependencies) {
                    var scene = new Scene3D();
                    if (sceneDef.name !== undefined)
                        scene.name = sceneDef.name;
                    // assignExtrasToUserData(scene, sceneDef);
                    // if (sceneDef.extensions) addUnknownExtensionsToUserData(extensions, scene, sceneDef);
                    var nodeIds = sceneDef.nodes || [];
                    for (var i = 0, il = nodeIds.length; i < il; i++) {
                        buildNodeHierachy(nodeIds[i], scene, json, dependencies.nodes, dependencies.skins);
                    }
                    return scene;
                });
            };
        }();
        // this.fileLoader = new THREE.FileLoader(this.options.manager);
        // this.fileLoader.setResponseType('arraybuffer');
    }
    GLTFParser.prototype.parse = function (onLoad, onError) {
        var json = this.json;
        // Clear the loader cache
        this.cache.removeAll();
        // Mark the special nodes/meshes in json for efficient parse
        this.markDefs();
        // Fire the callback on complete
        this.getMultiDependencies([
            'scene',
            'animation',
            'camera'
        ]).then(function (dependencies) {
            var scenes = dependencies.scenes || [];
            var scene = scenes[json.scene || 0];
            var animations = dependencies.animations || [];
            var cameras = dependencies.cameras || [];
            onLoad(scene, scenes, cameras, animations, json);
        }).catch(onError);
    };
    /**
     * Marks the special nodes/meshes in json for efficient parse.
     */
    GLTFParser.prototype.markDefs = function () {
        var nodeDefs = this.json.nodes || [];
        var skinDefs = this.json.skins || [];
        var meshDefs = this.json.meshes || [];
        var meshReferences = {};
        var meshUses = {};
        // Nothing in the node definition indicates whether it is a Bone or an
        // Object3D. Use the skins' joint references to mark bones.
        for (var skinIndex = 0, skinLength = skinDefs.length; skinIndex < skinLength; skinIndex++) {
            var joints = skinDefs[skinIndex].joints;
            for (var i = 0, il = joints.length; i < il; i++) {
                nodeDefs[joints[i]].isBone = true;
            }
        }
        // Meshes can (and should) be reused by multiple nodes in a glTF asset. To
        // avoid having more than one THREE.Mesh with the same name, count
        // references and rename instances below.
        //
        // Example: CesiumMilkTruck sample model reuses "Wheel" meshes.
        for (var nodeIndex = 0, nodeLength = nodeDefs.length; nodeIndex < nodeLength; nodeIndex++) {
            var nodeDef = nodeDefs[nodeIndex];
            if (nodeDef.mesh !== undefined) {
                if (meshReferences[nodeDef.mesh] === undefined) {
                    meshReferences[nodeDef.mesh] = meshUses[nodeDef.mesh] = 0;
                }
                meshReferences[nodeDef.mesh]++;
                // Nothing in the mesh definition indicates whether it is
                // a SkinnedMesh or Mesh. Use the node's mesh reference
                // to mark SkinnedMesh if node has skin.
                if (nodeDef.skin !== undefined) {
                    meshDefs[nodeDef.mesh].isSkinnedMesh = true;
                }
            }
        }
        this.json.meshReferences = meshReferences;
        this.json.meshUses = meshUses;
    };
    /**
     * Requests the specified dependency asynchronously, with caching.
     * @param {string} type
     * @param {number} index
     * @return {Promise<Object>}
     */
    GLTFParser.prototype.getDependency = function (type, index) {
        var cacheKey = type + ':' + index;
        var dependency = this.cache.get(cacheKey);
        if (!dependency) {
            switch (type) {
                case 'scene':
                    dependency = this.loadScene(index);
                    break;
                case 'node':
                    dependency = this.loadNode(index);
                    break;
                case 'mesh':
                    dependency = this.loadMesh(index);
                    break;
                case 'accessor':
                    dependency = this.loadAccessor(index);
                    break;
                case 'bufferView':
                    dependency = this.loadBufferView(index);
                    break;
                case 'buffer':
                    dependency = this.loadBuffer(index);
                    break;
                case 'material':
                    dependency = this.loadMaterial(index);
                    break;
                case 'texture':
                    dependency = this.loadTexture(index);
                    break;
                case 'skin':
                    dependency = this.loadSkin(index);
                    break;
                case 'animation':
                    dependency = this.loadAnimation(index);
                    break;
                case 'camera':
                    dependency = this.loadCamera(index);
                    break;
                default:
                    throw new Error('Unknown type: ' + type);
            }
            this.cache.add(cacheKey, dependency);
        }
        return dependency;
    };
    /**
     * Requests all dependencies of the specified type asynchronously, with caching.
     * @param {string} type
     * @return {Promise<Array<Object>>}
     */
    GLTFParser.prototype.getDependencies = function (type) {
        var dependencies = this.cache.get(type);
        if (!dependencies) {
            var parser = this;
            var defs = this.json[type + (type === 'mesh' ? 'es' : 's')] || [];
            dependencies = Promise.all(defs.map(function (def, index) {
                return parser.getDependency(type, index);
            }));
            this.cache.add(type, dependencies);
        }
        return dependencies;
    };
    /**
     * Requests all multiple dependencies of the specified types asynchronously, with caching.
     * @param {Array<string>} types
     * @return {Promise<Object<Array<Object>>>}
     */
    GLTFParser.prototype.getMultiDependencies = function (types) {
        var results = {};
        var pendings = [];
        for (var i = 0, il = types.length; i < il; i++) {
            var type = types[i];
            var value = this.getDependencies(type);
            value = value.then(function (key, value) {
                results[key] = value;
            }.bind(this, type + (type === 'mesh' ? 'es' : 's')));
            pendings.push(value);
        }
        return Promise.all(pendings).then(function () {
            return results;
        });
    };
    /**
     * ok
     * @param {number} bufferIndex
     * @return {Promise<ArrayBuffer>}
     */
    GLTFParser.prototype.loadBuffer = function (bufferIndex) {
        //基本只需要一次，而且没有bufferDef.uri
        var bufferDef = this.json.buffers[bufferIndex];
        // var loader = this.fileLoader;
        if (bufferDef.type && bufferDef.type !== 'arraybuffer') {
            throw new Error('GLTFLoader: ' + bufferDef.type + ' buffer type is not supported.');
        }
        // If present, GLB container is required to be the first buffer.
        if (bufferDef.uri === undefined && bufferIndex === 0) {
            return Promise.resolve(this.extensions[EXTENSIONS.KHR_BINARY_GLTF].body);
        }
        //基本不用其他的加载
        // var options = this.options;
        return new Promise(function (resolve, reject) {
            //考虑下base64的加载，其他路径的再说
            // if (/^data:.*,.*$/i.test(bufferDef.uri)) {
            var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
            var dataUriRegexResult = bufferDef.uri.match(dataUriRegex);
            if (dataUriRegexResult) {
                dataUriRegexResult[1];
                var isBase64 = !!dataUriRegexResult[2];
                var data = dataUriRegexResult[3];
                data = decodeURIComponent(data);
                if (isBase64)
                    data = (window && window.atob || atob_base64Decode)(data); //考虑小程序兼容性
                var view = new Uint8Array(data.length);
                for (var i = 0; i < data.length; i++) {
                    view[i] = data.charCodeAt(i);
                }
                resolve(view.buffer);
                return;
            }
            // };
            reject();
            // loader.load(resolveURL(bufferDef.uri, options.path), resolve, undefined, function () {
            // 	reject(new Error('THREE.GLTFLoader: Failed to load buffer "' + bufferDef.uri + '".'));
            // });
        });
    };
    /**
     * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views
     * @param {number} bufferViewIndex
     * @return {Promise<ArrayBuffer>}
     */
    GLTFParser.prototype.loadBufferView = function (bufferViewIndex) {
        var bufferViewDef = this.json.bufferViews[bufferViewIndex];
        return this.getDependency('buffer', bufferViewDef.buffer).then(function (buffer) {
            var byteLength = bufferViewDef.byteLength || 0;
            var byteOffset = bufferViewDef.byteOffset || 0;
            return buffer.slice(byteOffset, byteOffset + byteLength);
        });
    };
    /**
     * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#accessors
     * @param {number} accessorIndex
     * @return {Promise<BufferAttribute|InterleavedBufferAttribute>}
     */
    GLTFParser.prototype.loadAccessor = function (accessorIndex) {
        var parser = this;
        var json = this.json;
        var accessorDef = this.json.accessors[accessorIndex];
        if (accessorDef.bufferView === undefined && accessorDef.sparse === undefined) {
            // Ignore empty accessors, which may be used to declare runtime
            // information about attributes coming from another source (e.g. Draco
            // compression extension).
            return null;
        }
        var pendingBufferViews = [];
        if (accessorDef.bufferView !== undefined) {
            pendingBufferViews.push(this.getDependency('bufferView', accessorDef.bufferView));
        }
        else {
            pendingBufferViews.push(null);
        }
        if (accessorDef.sparse !== undefined) {
            pendingBufferViews.push(this.getDependency('bufferView', accessorDef.sparse.indices.bufferView));
            pendingBufferViews.push(this.getDependency('bufferView', accessorDef.sparse.values.bufferView));
        }
        return Promise.all(pendingBufferViews).then(function (bufferViews) {
            var bufferView = bufferViews[0];
            var itemSize = WEBGL_TYPE_SIZES[accessorDef.type];
            var TypedArray = WEBGL_COMPONENT_TYPES[accessorDef.componentType];
            // For VEC3: itemSize is 3, elementBytes is 4, itemBytes is 12.
            var elementBytes = TypedArray.BYTES_PER_ELEMENT;
            var itemBytes = elementBytes * itemSize;
            var byteOffset = accessorDef.byteOffset || 0;
            var byteStride = accessorDef.bufferView !== undefined ? json.bufferViews[accessorDef.bufferView].byteStride : undefined;
            var normalized = accessorDef.normalized === true;
            var array, bufferAttribute; //| InterleavedBufferAttribute;
            // The buffer is not interleaved if the stride is the item size in bytes.
            if (byteStride && byteStride !== itemBytes) {
                var ibCacheKey = 'InterleavedBuffer:' + accessorDef.bufferView + ':' + accessorDef.componentType;
                var ib = parser.cache.get(ibCacheKey);
                if (!ib) {
                    // Use the full buffer if it's interleaved.
                    array = new TypedArray(bufferView);
                    // Integer parameters to IB/IBA are in array elements, not bytes.
                    ib = new InterleavedBuffer(array, byteStride / elementBytes);
                    parser.cache.add(ibCacheKey, ib);
                }
                // bufferAttribute = new InterleavedBufferAttribute(ib, itemSize, byteOffset / elementBytes, normalized)
                bufferAttribute = cloneBufferAttribute(new InterleavedBufferAttribute(ib, itemSize, byteOffset / elementBytes, normalized));
            }
            else {
                if (bufferView === null) {
                    array = new TypedArray(accessorDef.count * itemSize);
                }
                else {
                    array = new TypedArray(bufferView, byteOffset, accessorDef.count * itemSize);
                }
                bufferAttribute = new BufferAttribute(array, itemSize, normalized);
            }
            // https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#sparse-accessors
            if (accessorDef.sparse !== undefined) {
                var itemSizeIndices = WEBGL_TYPE_SIZES.SCALAR;
                var TypedArrayIndices = WEBGL_COMPONENT_TYPES[accessorDef.sparse.indices.componentType];
                var byteOffsetIndices = accessorDef.sparse.indices.byteOffset || 0;
                var byteOffsetValues = accessorDef.sparse.values.byteOffset || 0;
                var sparseIndices = new TypedArrayIndices(bufferViews[1], byteOffsetIndices, accessorDef.sparse.count * itemSizeIndices);
                var sparseValues = new TypedArray(bufferViews[2], byteOffsetValues, accessorDef.sparse.count * itemSize);
                if (bufferView !== null) {
                    //@ts-ignore Avoid modifying the original ArrayBuffer, if the bufferView wasn't initialized with zeroes.
                    bufferAttribute.setArray(bufferAttribute.array.slice());
                }
                for (var i = 0, il = sparseIndices.length; i < il; i++) {
                    var index = sparseIndices[i];
                    bufferAttribute.setX(index, sparseValues[i * itemSize]);
                    if (itemSize >= 2)
                        bufferAttribute.setY(index, sparseValues[i * itemSize + 1]);
                    if (itemSize >= 3)
                        bufferAttribute.setZ(index, sparseValues[i * itemSize + 2]);
                    if (itemSize >= 4)
                        bufferAttribute.setW(index, sparseValues[i * itemSize + 3]);
                    if (itemSize >= 5)
                        throw new Error('GLTFLoader: Unsupported itemSize in sparse BufferAttribute.');
                }
            }
            return bufferAttribute;
        });
    };
    /**
     * ok
     * @param {number} textureIndex
     * @return {Promise<Texture>}
     */
    GLTFParser.prototype.loadTexture = function (textureIndex) {
        var parser = this;
        var json = this.json;
        this.options;
        // var textureLoader = this.textureLoader;
        // var URL = window.URL// || window.webkitURL;
        var textureDef = json.textures[textureIndex];
        var textureExtensions = textureDef.extensions || {};
        var source;
        if (textureExtensions[EXTENSIONS.MSFT_TEXTURE_DDS]) {
            source = json.images[textureExtensions[EXTENSIONS.MSFT_TEXTURE_DDS].source];
        }
        else {
            source = json.images[textureDef.source];
        }
        var sourceURI = source.uri;
        // var isObjectURL = false;
        if (source.bufferView !== undefined) {
            // Load binary image data from bufferView, if provided.
            sourceURI = parser.getDependency('bufferView', source.bufferView).then(function (bufferView) {
                // if (window.arrayBufferToBase64 != undefined) {
                var base64 = ArrayBufferToBase64(bufferView);
                var base64String = "data:" + source.mimeType + ";base64," + base64;
                return base64String;
                // }
                // isObjectURL = true;
                // var blob = new Blob([bufferView], { type: source.mimeType });
                // sourceURI = URL.createObjectURL(blob);
                // return sourceURI;
            });
        }
        return Promise.resolve(sourceURI).then(function (sourceURI) {
            // Load Texture resource.
            // var loader = THREE.Loader.Handlers.get(sourceURI);
            // if (!loader) {
            // 	loader = textureExtensions[EXTENSIONS.MSFT_TEXTURE_DDS]
            // 		? parser.extensions[EXTENSIONS.MSFT_TEXTURE_DDS].ddsLoader
            // 		: textureLoader;
            // }
            return new Promise(function (resolve, reject) {
                GlobalLoader.loadImage(function (s, image) {
                    if (s) {
                        resolve(Texture.fromImage(image));
                    }
                    else {
                        reject();
                    }
                }, resolveURL(sourceURI, "" /*options.path*/));
                // loader.load(resolveURL(sourceURI, options.path), resolve, undefined, reject);
            });
        }).then(function (texture) {
            // Clean up resources and configure Texture.
            // if (isObjectURL === true) {
            // 	URL.revokeObjectURL(sourceURI);
            // }
            // texture.flipY = false;
            if (textureDef.name !== undefined)
                texture["name"] = textureDef.name;
            // Ignore unknown mime types, like DDS files.
            // if (source.mimeType in MIME_TYPE_FORMATS) {
            // 	texture.format = MIME_TYPE_FORMATS[source.mimeType];
            // }
            // var samplers = json.samplers || {};
            // var sampler = samplers[textureDef.sampler] || {};
            // texture.magFilter = WEBGL_FILTERS[sampler.magFilter] || THREE.LinearFilter;
            // texture.minFilter = WEBGL_FILTERS[sampler.minFilter] || THREE.LinearMipMapLinearFilter;
            // texture.wrapS = WEBGL_WRAPPINGS[sampler.wrapS] || THREE.RepeatWrapping;
            // texture.wrapT = WEBGL_WRAPPINGS[sampler.wrapT] || THREE.RepeatWrapping;
            return texture;
        });
    };
    /**
     * Asynchronously assigns a texture to the given material parameters.
     * @param {Object} materialParams
     * @param {string} textureName
     * @param {number} textureIndex
     * @return {Promise}
     */
    GLTFParser.prototype.assignTexture = function (materialParams, textureName, textureIndex) {
        return this.getDependency('texture', textureIndex).then(function (texture) {
            materialParams[textureName] = texture;
        });
    };
    /**
     * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#materials
     * @param {number} materialIndex
     * @return {Promise<Material>}
     */
    GLTFParser.prototype.loadMaterial = function (materialIndex) {
        var parser = this;
        var json = this.json;
        this.extensions;
        var materialDef = json.materials[materialIndex];
        var materialType;
        var materialParams = {};
        var materialExtensions = materialDef.extensions || {};
        var pending = [];
        if (materialExtensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS]) {
            // var sgExtension = extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS];
            // materialType = sgExtension.getMaterialType(materialDef);
            // pending.push(sgExtension.extendParams(materialParams, materialDef, parser));
            //先将扩展简单处理
            materialType = LightMaterial;
            var pbrSpecularGlossiness = materialDef.extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS];
            materialParams.color = 0xffffff;
            materialParams.alpha = 1.0;
            if (Array.isArray(pbrSpecularGlossiness.diffuseFactor)) {
                var array = pbrSpecularGlossiness.diffuseFactor;
                materialParams.color = rgb2hex$1(array);
                materialParams.alpha = array[3];
            }
            if (pbrSpecularGlossiness.diffuseTexture !== undefined) {
                pending.push(parser.assignTexture(materialParams, 'map', pbrSpecularGlossiness.diffuseTexture.index));
            }
        }
        // else if (materialExtensions[EXTENSIONS.KHR_MATERIALS_UNLIT]) {
        // 	var kmuExtension = extensions[EXTENSIONS.KHR_MATERIALS_UNLIT];
        // 	materialType = kmuExtension.getMaterialType(materialDef);
        // 	pending.push(kmuExtension.extendParams(materialParams, materialDef, parser));
        // } //上面这种就简单点，加到下面
        else {
            // Specification:
            // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#metallic-roughness-material
            materialType = materialExtensions[EXTENSIONS.KHR_MATERIALS_UNLIT] ? BaseMaterial : LightMaterial; //THREE.MeshStandardMaterial;
            var metallicRoughness = materialDef.pbrMetallicRoughness || {};
            materialParams.color = 0xffffff;
            materialParams.alpha = 1.0;
            //颜色透明度
            if (Array.isArray(metallicRoughness.baseColorFactor)) {
                var array = metallicRoughness.baseColorFactor;
                materialParams.color = rgb2hex$1(array);
                materialParams.alpha = array[3];
            }
            //贴图
            if (metallicRoughness.baseColorTexture !== undefined) {
                pending.push(parser.assignTexture(materialParams, 'map', metallicRoughness.baseColorTexture.index));
            }
            // materialParams.metalness = metallicRoughness.metallicFactor !== undefined ? metallicRoughness.metallicFactor : 1.0;
            // materialParams.roughness = metallicRoughness.roughnessFactor !== undefined ? metallicRoughness.roughnessFactor : 1.0;
            // if (metallicRoughness.metallicRoughnessTexture !== undefined) {
            // 	var textureIndex = metallicRoughness.metallicRoughnessTexture.index;
            // 	pending.push(parser.assignTexture(materialParams, 'metalnessMap', textureIndex));
            // 	pending.push(parser.assignTexture(materialParams, 'roughnessMap', textureIndex));
            // }
        }
        if (materialDef.doubleSided === true) {
            materialParams.side = RenderSideType.DoubleSide;
        }
        // var alphaMode = materialDef.alphaMode || ALPHA_MODES.OPAQUE;
        // if (alphaMode === ALPHA_MODES.BLEND) {
        // 	materialParams.transparent = true;
        // } else {
        // 	materialParams.transparent = false;
        // 	if (alphaMode === ALPHA_MODES.MASK) {
        // 		materialParams.alphaTest = materialDef.alphaCutoff !== undefined ? materialDef.alphaCutoff : 0.5;
        // 	}
        // }
        // if (materialDef.normalTexture !== undefined && materialType !== THREE.MeshBasicMaterial) {
        // 	pending.push(parser.assignTexture(materialParams, 'normalMap', materialDef.normalTexture.index));
        // 	materialParams.normalScale = new THREE.Vector2(1, 1);
        // 	if (materialDef.normalTexture.scale !== undefined) {
        // 		materialParams.normalScale.set(materialDef.normalTexture.scale, materialDef.normalTexture.scale);
        // 	}
        // }
        // if (materialDef.occlusionTexture !== undefined && materialType !== THREE.MeshBasicMaterial) {
        // 	pending.push(parser.assignTexture(materialParams, 'aoMap', materialDef.occlusionTexture.index));
        // 	if (materialDef.occlusionTexture.strength !== undefined) {
        // 		materialParams.aoMapIntensity = materialDef.occlusionTexture.strength;
        // 	}
        // }
        // if (materialDef.emissiveFactor !== undefined && materialType !== THREE.MeshBasicMaterial) {
        // 	materialParams.emissive = new THREE.Color().fromArray(materialDef.emissiveFactor);
        // }
        // if (materialDef.emissiveTexture !== undefined && materialType !== THREE.MeshBasicMaterial) {
        // 	pending.push(parser.assignTexture(materialParams, 'emissiveMap', materialDef.emissiveTexture.index));
        // }
        return Promise.all(pending).then(function () {
            var material;
            // if (materialType === THREE.ShaderMaterial) {
            // 	material = extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS].createMaterial(materialParams);
            // } else {
            //@ts-ignore
            material = new materialType(materialParams);
            // }
            //@ts-ignore
            if (materialDef.name !== undefined)
                material.name = materialDef.name;
            // Normal map textures use OpenGL conventions:
            // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#materialnormaltexture
            // if (material.normalScale) {
            // 	material.normalScale.y = - material.normalScale.y;
            // }
            // baseColorTexture, emissiveTexture, and specularGlossinessTexture use sRGB encoding.
            // if (material.map) material.map.encoding = THREE.sRGBEncoding;
            // if (material.emissiveMap) material.emissiveMap.encoding = THREE.sRGBEncoding;
            // if (material.specularMap) material.specularMap.encoding = THREE.sRGBEncoding;
            // assignExtrasToUserData(material, materialDef);
            // if (materialDef.extensions) addUnknownExtensionsToUserData(extensions, material, materialDef);
            return material;
        });
    };
    /**
     * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#geometry
     *
     * Creates BufferGeometries from primitives.
     * If we can build a single BufferGeometry with .groups from multiple primitives, returns one BufferGeometry.
     * Otherwise, returns BufferGeometries without .groups as many as primitives.
     *
     * @param {Array<Object>} primitives
     * @return {Promise<Array<BufferGeometry>>}
     */
    GLTFParser.prototype.loadGeometries = function (primitives) {
        this.extensions;
        var cache = this.primitiveCache;
        // var isMultiPass = isMultiPassGeometry(primitives);
        // var originalPrimitives;
        // if (isMultiPass) {
        // 	originalPrimitives = primitives; // save original primitives and use later
        // 	// We build a single BufferGeometry with .groups from multiple primitives
        // 	// because all primitives share the same attributes/morph/mode and have indices.
        // 	primitives = [primitives[0]];
        // 	// Sets .groups and combined indices to a geometry later in this method.
        // }
        return this.getDependencies('accessor').then(function (accessors) {
            var pending = [];
            for (var i = 0, il = primitives.length; i < il; i++) {
                var primitive = primitives[i];
                // See if we've already created this geometry
                var cached = getCachedGeometry(cache, primitive);
                if (cached) {
                    // Use the cached geometry if it exists
                    pending.push(cached);
                }
                else if (primitive.extensions && primitive.extensions[EXTENSIONS.KHR_DRACO_MESH_COMPRESSION]) ;
                else {
                    // Otherwise create a new geometry
                    // var geometry = new Geometry();
                    var geometry = addPrimitiveAttributes(primitive, accessors);
                    var geometryPromise = Promise.resolve(geometry);
                    // Cache this geometry
                    cache.push({ primitive: primitive, promise: geometryPromise });
                    pending.push(geometryPromise);
                }
            }
            return Promise.all(pending).then(function (geometries) {
                // if (isMultiPass) {
                // 	var baseGeometry = geometries[0];
                // 	// See if we've already created this combined geometry
                // 	var cache = parser.multiPassGeometryCache;
                // 	var cached = getCachedMultiPassGeometry(cache, baseGeometry, originalPrimitives);
                // 	if (cached !== null) return [cached.geometry];
                // 	// Cloning geometry because of index override.
                // 	// Attributes can be reused so cloning by myself here.
                // 	// NORMAL: 2
                // 	// POSITION: 1
                // 	// TEXCOORD_0: 3
                // 	//顶点
                // 	var _vertices = [];
                // 	var geometry = new Geometry();
                // 	geometry["name"] = baseGeometry.name;
                // 	geometry["userData"] = baseGeometry.userData;
                // 	for (var key in baseGeometry.attributes) geometry.addAttribute(key, baseGeometry.attributes[key]);
                // 	for (var key in baseGeometry.morphAttributes) geometry.morphAttributes[key] = baseGeometry.morphAttributes[key];
                // 	var indices = [];
                // 	var offset = 0;
                // 	for (var i = 0, il = originalPrimitives.length; i < il; i++) {
                // 		var accessor = accessors[originalPrimitives[i].indices];
                // 		for (var j = 0, jl = accessor.count; j < jl; j++) indices.push(accessor.array[j]);
                // 		geometry.addGroup(offset, accessor.count, i);
                // 		offset += accessor.count;
                // 	}
                // 	geometry.setIndex(indices);
                // 	cache.push({ geometry: geometry, baseGeometry: baseGeometry, primitives: originalPrimitives });
                // 	return [geometry];
                // } 
                // else if (geometries.length > 1 && THREE.BufferGeometryUtils !== undefined) {
                // 	// Tries to merge geometries with BufferGeometryUtils if possible
                // 	for (var i = 1, il = primitives.length; i < il; i++) {
                // 		// can't merge if draw mode is different
                // 		if (primitives[0].mode !== primitives[i].mode) return geometries;
                // 	}
                // 	// See if we've already created this combined geometry
                // 	var cache = parser.multiplePrimitivesCache;
                // 	var cached = getCachedCombinedGeometry(cache, geometries);
                // 	if (cached) {
                // 		if (cached.geometry !== null) return [cached.geometry];
                // 	} else {
                // 		var geometry = THREE.BufferGeometryUtils.mergeBufferGeometries(geometries, true);
                // 		cache.push({ geometry: geometry, baseGeometries: geometries });
                // 		if (geometry !== null) return [geometry];
                // 	}
                // }
                return geometries;
            });
        });
    };
    /**
     * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#meshes
     * @param {number} meshIndex
     * @return {Promise<Object3D|Mesh3D>}
     */
    GLTFParser.prototype.loadMesh = function (meshIndex) {
        var scope = this;
        var json = this.json;
        this.extensions;
        var meshDef = json.meshes[meshIndex];
        return this.getMultiDependencies([
            'accessor',
            'material'
        ]).then(function (dependencies) {
            var primitives = meshDef.primitives;
            var originalMaterials = [];
            for (var i = 0, il = primitives.length; i < il; i++) {
                originalMaterials[i] = primitives[i].material === undefined
                    ? createDefaultMaterial()
                    : dependencies.materials[primitives[i].material];
            }
            return scope.loadGeometries(primitives).then(function (geometries) {
                var meshes = [];
                for (var i = 0, il = geometries.length; i < il; i++) {
                    var geometry = geometries[i];
                    var primitive = primitives[i];
                    // 1. create Mesh
                    var mesh;
                    // var material = isMultiMaterial ? originalMaterials : originalMaterials[i];
                    var material = originalMaterials[i];
                    if (primitive.mode === WEBGL_CONSTANTS.TRIANGLES ||
                        primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ||
                        primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ||
                        primitive.mode === undefined) {
                        // .isSkinnedMesh isn't in glTF spec. See .markDefs()
                        mesh = meshDef.isSkinnedMesh === true
                            ? new SkinnedMesh3D(geometry, material)
                            : new Mesh3D(geometry, material);
                        // mesh = new Mesh3D(geometry, material);
                        if (mesh.instanceType === "SkinnedMesh3D") {
                            // we normalize floating point skin weight array to fix malformed assets (see #15319)
                            // it's important to skip this for non-float32 data since normalizeSkinWeights assumes non-normalized inputs
                            //@ts-ignore
                            mesh.normalizeSkinWeights();
                        }
                        // if (primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP) {
                        // 	mesh.drawMode = THREE.TriangleStripDrawMode;
                        // } else if (primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN) {
                        // 	mesh.drawMode = THREE.TriangleFanDrawMode;
                        // }
                    }
                    // else if (primitive.mode === WEBGL_CONSTANTS.LINES) {
                    // 	mesh = new THREE.LineSegments(geometry, material);
                    // } else if (primitive.mode === WEBGL_CONSTANTS.LINE_STRIP) {
                    // 	mesh = new THREE.Line(geometry, material);
                    // } else if (primitive.mode === WEBGL_CONSTANTS.LINE_LOOP) {
                    // 	mesh = new THREE.LineLoop(geometry, material);
                    // } else if (primitive.mode === WEBGL_CONSTANTS.POINTS) {
                    // 	mesh = new THREE.Points(geometry, material);
                    // } 
                    else {
                        throw new Error('GLTFLoader: Primitive mode unsupported: ' + primitive.mode);
                    }
                    // if (Object.keys(mesh.geometry.morphAttributes).length > 0) {
                    // 	updateMorphTargets(mesh, meshDef);
                    // }
                    //变形的权重加上
                    if (mesh.geometry._morphPositions)
                        updateMorphTargets(mesh, meshDef);
                    mesh.name = meshDef.name || ('mesh_' + meshIndex);
                    if (geometries.length > 1)
                        mesh.name += '_' + i;
                    // assignExtrasToUserData(mesh, meshDef);
                    meshes.push(mesh);
                    // 2. update Material depending on Mesh and BufferGeometry
                    // var materials = isMultiMaterial ? mesh.material : [mesh.material];
                    var material = mesh.material;
                    // var useVertexColors = geometry.attributes.color !== undefined;
                    // var useFlatShading = geometry.attributes.normal === undefined;
                    var useSkinning = mesh.instanceType == "SkinnedMesh3D";
                    var useMorphTargets = !!geometry._morphPositions;
                    var useMorphNormals = useMorphTargets && !!geometry._morphNormals;
                    //用相同的材质有覆盖的风险，所以有才设置吧，反正mesh也会判断一次
                    // if (useMorphTargets) material.morphTargets = useMorphTargets;
                    // if (useMorphNormals) material.morphNormals = useMorphNormals;
                    if ( /*useVertexColors || useFlatShading ||*/useSkinning || useMorphTargets) {
                        var cacheKey = 'ClonedMaterial:' + material.instanceId + ':';
                        // if (material.isGLTFSpecularGlossinessMaterial) cacheKey += 'specular-glossiness:';
                        if (useSkinning)
                            cacheKey += 'skinning:';
                        // if (useVertexColors) cacheKey += 'vertex-colors:';
                        // if (useFlatShading) cacheKey += 'flat-shading:';
                        if (useMorphTargets)
                            cacheKey += 'morph-targets:';
                        if (useMorphNormals)
                            cacheKey += 'morph-normals:';
                        var cachedMaterial = scope.cache.get(cacheKey);
                        if (!cachedMaterial) {
                            cachedMaterial = /*material.isGLTFSpecularGlossinessMaterial
                                ? extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS].cloneMaterial(material)
                                :*/
                                material.clone();
                            if (useSkinning)
                                cachedMaterial.skinning = true;
                            // if (useVertexColors) cachedMaterial.vertexColors = THREE.VertexColors;
                            // if (useFlatShading) cachedMaterial.flatShading = true;
                            if (useMorphTargets)
                                cachedMaterial.morphTargets = true;
                            if (useMorphNormals)
                                cachedMaterial.morphNormals = true;
                            scope.cache.add(cacheKey, cachedMaterial);
                        }
                        material = cachedMaterial;
                    }
                    mesh.material = material;
                    // for (var j = 0, jl = materials.length; j < jl; j++) {
                    // 	var material = materials[j];
                    // 	if (mesh.isPoints) {
                    // 		var cacheKey = 'PointsMaterial:' + material.uuid;
                    // 		var pointsMaterial = scope.cache.get(cacheKey);
                    // 		if (!pointsMaterial) {
                    // 			pointsMaterial = new THREE.PointsMaterial();
                    // 			THREE.Material.prototype.copy.call(pointsMaterial, material);
                    // 			pointsMaterial.color.copy(material.color);
                    // 			pointsMaterial.map = material.map;
                    // 			pointsMaterial.lights = false; // PointsMaterial doesn't support lights yet
                    // 			scope.cache.add(cacheKey, pointsMaterial);
                    // 		}
                    // 		material = pointsMaterial;
                    // 	} else if (mesh.isLine) {
                    // 		var cacheKey = 'LineBasicMaterial:' + material.uuid;
                    // 		var lineMaterial = scope.cache.get(cacheKey);
                    // 		if (!lineMaterial) {
                    // 			lineMaterial = new THREE.LineBasicMaterial();
                    // 			THREE.Material.prototype.copy.call(lineMaterial, material);
                    // 			lineMaterial.color.copy(material.color);
                    // 			lineMaterial.lights = false; // LineBasicMaterial doesn't support lights yet
                    // 			scope.cache.add(cacheKey, lineMaterial);
                    // 		}
                    // 		material = lineMaterial;
                    // 	}
                    // 	// Clone the material if it will be modified
                    // 	if (useVertexColors || useFlatShading || useSkinning || useMorphTargets) {
                    // 		var cacheKey = 'ClonedMaterial:' + material.uuid + ':';
                    // 		if (material.isGLTFSpecularGlossinessMaterial) cacheKey += 'specular-glossiness:';
                    // 		if (useSkinning) cacheKey += 'skinning:';
                    // 		if (useVertexColors) cacheKey += 'vertex-colors:';
                    // 		if (useFlatShading) cacheKey += 'flat-shading:';
                    // 		if (useMorphTargets) cacheKey += 'morph-targets:';
                    // 		if (useMorphNormals) cacheKey += 'morph-normals:';
                    // 		var cachedMaterial = scope.cache.get(cacheKey);
                    // 		if (!cachedMaterial) {
                    // 			cachedMaterial = material.isGLTFSpecularGlossinessMaterial
                    // 				? extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS].cloneMaterial(material)
                    // 				: material.clone();
                    // 			if (useSkinning) cachedMaterial.skinning = true;
                    // 			if (useVertexColors) cachedMaterial.vertexColors = THREE.VertexColors;
                    // 			if (useFlatShading) cachedMaterial.flatShading = true;
                    // 			if (useMorphTargets) cachedMaterial.morphTargets = true;
                    // 			if (useMorphNormals) cachedMaterial.morphNormals = true;
                    // 			scope.cache.add(cacheKey, cachedMaterial);
                    // 		}
                    // 		material = cachedMaterial;
                    // 	}
                    // 	materials[j] = material;
                    // 	// workarounds for mesh and geometry
                    // 	//暂时不管这个aoMap
                    // 	// if (material.aoMap && geometry.attributes.uv2 === undefined && geometry.attributes.uv !== undefined) {
                    // 	// 	console.log('THREE.GLTFLoader: Duplicating UVs to support aoMap.');
                    // 	// 	geometry.addAttribute('uv2', new THREE.BufferAttribute(geometry.attributes.uv.array, 2));
                    // 	// }
                    // 	if (material.isGLTFSpecularGlossinessMaterial) {
                    // 		// for GLTFSpecularGlossinessMaterial(ShaderMaterial) uniforms runtime update
                    // 		mesh.onBeforeRender = extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS].refreshUniforms;
                    // 	}
                    // }
                    // mesh.material = isMultiMaterial ? materials : materials[0];
                }
                if (meshes.length === 1) {
                    return meshes[0];
                }
                var group = new Object3D();
                for (var i = 0; i < meshes.length; i++) {
                    group.addChild(meshes[i]);
                }
                return group;
            });
        });
    };
    /**
     * ok
     * @param {number} cameraIndex
     * @return {Promise<PerspectiveCamera>}
     */
    GLTFParser.prototype.loadCamera = function (cameraIndex) {
        var camera;
        var cameraDef = this.json.cameras[cameraIndex];
        var params = cameraDef[cameraDef.type];
        if (!params) {
            console.warn('model camera params error');
            return;
        }
        if (cameraDef.type === 'perspective') {
            camera = new PerspectiveCamera(RAD_TO_DEG * params.yfov, params.aspectRatio || 1, params.znear || 1, params.zfar || 2e6);
        }
        // else if (cameraDef.type === 'orthographic') {
        // 	camera = new THREE.OrthographicCamera(params.xmag / - 2, params.xmag / 2, params.ymag / 2, params.ymag / - 2, params.znear, params.zfar);
        // }
        if (cameraDef.name !== undefined)
            camera.name = cameraDef.name;
        // assignExtrasToUserData(camera, cameraDef);
        return Promise.resolve(camera);
    };
    /**
     * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins
     * @param {number} skinIndex
     * @return {Promise<Object>}
     */
    GLTFParser.prototype.loadSkin = function (skinIndex) {
        var skinDef = this.json.skins[skinIndex];
        var skinEntry = { joints: skinDef.joints };
        if (skinDef.inverseBindMatrices === undefined) {
            return Promise.resolve(skinEntry);
        }
        return this.getDependency('accessor', skinDef.inverseBindMatrices).then(function (accessor) {
            skinEntry.inverseBindMatrices = accessor;
            return skinEntry;
        });
    };
    /**
     * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#animations
     * @param {number} animationIndex
     * @return {Promise<AnimationClip>}
     */
    GLTFParser.prototype.loadAnimation = function (animationIndex) {
        var json = this.json;
        var animationDef = json.animations[animationIndex];
        return this.getMultiDependencies([
            'accessor',
            'node'
        ]).then(function (dependencies) {
            var tracks = [];
            for (var i = 0, il = animationDef.channels.length; i < il; i++) {
                var channel = animationDef.channels[i];
                var sampler = animationDef.samplers[channel.sampler];
                if (sampler) {
                    var target = channel.target;
                    var name = target.node !== undefined ? target.node : target.id; // NOTE: target.id is deprecated.
                    var input = animationDef.parameters !== undefined ? animationDef.parameters[sampler.input] : sampler.input;
                    var output = animationDef.parameters !== undefined ? animationDef.parameters[sampler.output] : sampler.output;
                    var inputAccessor = dependencies.accessors[input];
                    var outputAccessor = dependencies.accessors[output];
                    // console.log(2222222)
                    // console.log(inputAccessor)
                    // console.log(outputAccessor)
                    var node = dependencies.nodes[name];
                    // console.log("node:", node)
                    if (node) {
                        node.updateLocalMatrix();
                        var TypedKeyframeTrack;
                        switch (PATH_PROPERTIES[target.path]) {
                            case PATH_PROPERTIES.weights:
                                TypedKeyframeTrack = AnimationType3D.morphTargetInfluences;
                                // console.log("weights")
                                break;
                            case PATH_PROPERTIES.rotation:
                                TypedKeyframeTrack = AnimationType3D.quaternion;
                                // console.log("rotation")
                                break;
                            case PATH_PROPERTIES.position:
                                TypedKeyframeTrack = AnimationType3D.position;
                                break;
                            case PATH_PROPERTIES.scale:
                                TypedKeyframeTrack = AnimationType3D.scale;
                                break;
                            default:
                                TypedKeyframeTrack = AnimationType3D.position;
                                // console.log("position,scale")
                                break;
                        }
                        var targetName = node.name ? node.name : node.instanceId;
                        //TODO，暂时不用，以后用到再说
                        sampler.interpolation !== undefined ? INTERPOLATION[sampler.interpolation] : InterpolateLinear;
                        //处理顶点变形的权重
                        var targetNames = [];
                        if (PATH_PROPERTIES[target.path] === PATH_PROPERTIES.weights) {
                            // node can be THREE.Group here but
                            // PATH_PROPERTIES.weights(morphTargetInfluences) should be
                            // the property of a mesh object under group.
                            //递归处理 TODO
                            traverse(node, function (object) {
                                if ((object.instanceType === "Mesh3D" || object.instanceType === "SkinnedMesh3D") &&
                                    object["morphTargetInfluences"]) {
                                    targetNames.push(object.name ? object.name : object.instanceId);
                                }
                            });
                        }
                        else {
                            targetNames.push(targetName);
                        }
                        // console.log("targetNames:", targetNames)
                        // KeyframeTrack.optimize() will modify given 'times' and 'values'
                        // buffers before creating a truncated copy to keep. Because buffers may
                        // be reused by other tracks, make copies here.
                        for (var j = 0, jl = targetNames.length; j < jl; j++) {
                            // var track = new TypedKeyframeTrack(
                            // 	targetNames[j] + '.' + PATH_PROPERTIES[target.path],
                            // 	arraySlice(inputAccessor.array, 0),
                            // 	arraySlice(outputAccessor.array, 0),
                            // 	interpolation
                            // );
                            var track = new AnimationTrack3D(node, TypedKeyframeTrack, arraySlice(inputAccessor.array, 0), arraySlice(outputAccessor.array, 0));
                            // Here is the trick to enable custom interpolation.
                            // Overrides .createInterpolant in a factory method which creates custom interpolation.
                            // if (sampler.interpolation === 'CUBICSPLINE') {
                            // 	track.createInterpolant = function InterpolantFactoryMethodGLTFCubicSpline(result) {
                            // 		// A CUBICSPLINE keyframe in glTF has three output values for each input value,
                            // 		// representing inTangent, splineVertex, and outTangent. As a result, track.getValueSize()
                            // 		// must be divided by three to get the interpolant's sampleSize argument.
                            // 		return new GLTFCubicSplineInterpolant(this.times, this.values, this.getValueSize() / 3, result);
                            // 	};
                            // 	// Workaround, provide an alternate way to know if the interpolant type is cubis spline to track.
                            // 	// track.getInterpolation() doesn't return valid value for custom interpolant.
                            // 	track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline = true;
                            // }
                            tracks.push(track);
                        }
                    }
                }
            }
            var name = animationDef.name !== undefined ? animationDef.name : 'animation_' + animationIndex;
            // return new THREE.AnimationClip(name, undefined, tracks);
            //计算总时间
            var duration = 0;
            for (var i_1 = 0, n = tracks.length; i_1 !== n; ++i_1) {
                var tt = tracks[i_1];
                duration = Math.max(duration, tt.times[tt.times.length - 1]);
            }
            var clip = new AnimationClip(tracks, duration);
            clip.name = name;
            return clip;
        });
    };
    /**
     * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#nodes-and-hierarchy
     * @param {number} nodeIndex
     * @return {Promise<Object3D>}
     */
    GLTFParser.prototype.loadNode = function (nodeIndex) {
        var json = this.json;
        var extensions = this.extensions;
        var meshReferences = json.meshReferences;
        var meshUses = json.meshUses;
        var nodeDef = json.nodes[nodeIndex];
        return this.getMultiDependencies([
            'mesh',
            'skin',
            'camera',
            'light'
        ]).then(function (dependencies) {
            var node;
            // .isBone isn't in glTF spec. See .markDefs
            if (nodeDef.isBone === true) {
                node = new Bone3D();
                // return null//临时解决
            }
            else if (nodeDef.mesh !== undefined) {
                var mesh = dependencies.meshes[nodeDef.mesh];
                if (meshReferences[nodeDef.mesh] > 1) {
                    var instanceNum = meshUses[nodeDef.mesh]++;
                    node = mesh.clone();
                    node.name += '_instance_' + instanceNum;
                    // onBeforeRender copy for Specular-Glossiness
                    // node.onBeforeRender = mesh.onBeforeRender;
                    for (var i = 0, il = node.children.length; i < il; i++) {
                        node.children[i].name += '_instance_' + instanceNum;
                        // node.children[i].onBeforeRender = mesh.children[i].onBeforeRender;
                    }
                }
                else {
                    node = mesh;
                }
            }
            else if (nodeDef.camera !== undefined) {
                node = dependencies.cameras[nodeDef.camera];
            }
            else if (nodeDef.extensions
                && nodeDef.extensions[EXTENSIONS.KHR_LIGHTS_PUNCTUAL]
                && nodeDef.extensions[EXTENSIONS.KHR_LIGHTS_PUNCTUAL].light !== undefined) {
                var lights = extensions[EXTENSIONS.KHR_LIGHTS_PUNCTUAL].lights;
                node = lights[nodeDef.extensions[EXTENSIONS.KHR_LIGHTS_PUNCTUAL].light];
            }
            else {
                // node = new THREE.Object3D();
                node = new Object3D();
            }
            if (nodeDef.name !== undefined) {
                node.name = sanitizeNodeName(nodeDef.name);
                // node.name = "null";
            }
            // assignExtrasToUserData(node, nodeDef);
            // if (nodeDef.extensions) addUnknownExtensionsToUserData(extensions, node, nodeDef);
            if (nodeDef.matrix !== undefined) {
                var matrix = new Matrix4();
                matrix.fromArray(nodeDef.matrix);
                node.applyMatrix(matrix);
            }
            else {
                if (nodeDef.translation !== undefined) {
                    node.position.fromArray(nodeDef.translation);
                }
                if (nodeDef.rotation !== undefined) {
                    node.quaternion.fromArray(nodeDef.rotation);
                }
                if (nodeDef.scale !== undefined) {
                    node.scale.fromArray(nodeDef.scale);
                }
            }
            return node;
        });
    };
    return GLTFParser;
}());
/**
 *
 * @param  {GLTF.Primitive} primitiveDef
 * @param  {Array<BufferAttribute>} accessors
 */
function addPrimitiveAttributes(primitiveDef, accessors) {
    var attributes = primitiveDef.attributes;
    // POSITION: 1
    // NORMAL: 2
    // TEXCOORD_0: 3
    var verticesAttribute = accessors[attributes["POSITION"]];
    var normalAttribute = accessors[attributes["NORMAL"]];
    var uvAttribute = accessors[attributes["TEXCOORD_0"]] || accessors[attributes["TEXCOORD0"]];
    // var indices = [];
    // var vertices = [];
    // var normals = [];
    // var uvs = [];
    //取顶点数据
    // for (var gltfAttributeName in attributes) {
    // 	var threeAttributeName = ATTRIBUTES[gltfAttributeName];
    // 	var bufferAttribute = accessors[attributes[gltfAttributeName]];
    // 	// Skip attributes already provided by e.g. Draco extension.
    // 	if (!threeAttributeName) continue;
    // 	if (threeAttributeName in geometry.attributes) continue;
    // 	geometry.addAttribute(threeAttributeName, bufferAttribute);
    // }
    // if (primitiveDef.indices !== undefined && !geometry.index) {
    // 	geometry.setIndex(accessors[primitiveDef.indices]);
    // }
    var geo = new Geometry(attributeToArray(verticesAttribute), attributeToArray(accessors[primitiveDef.indices]), normalAttribute ? attributeToArray(normalAttribute) : null, null, uvAttribute ? attributeToArray(uvAttribute) : null);
    //骨骼相关的
    var skinWeight = accessors[attributes["WEIGHTS_0"]] || accessors[attributes["WEIGHTS"]];
    if (skinWeight)
        geo._skinWeight = attributeToArray(skinWeight);
    var skinIndex = accessors[attributes["JOINTS_0"]] || accessors[attributes["JOINT"]];
    if (skinIndex)
        geo._skinIndex = attributeToArray(skinIndex);
    //加变形的数据
    if (primitiveDef.targets !== undefined) {
        addMorphTargets(geo, primitiveDef.targets, accessors);
    }
    // assignExtrasToUserData(geometry, primitiveDef);
    return geo;
}
//用统一的，因为不止这里用到
// function decodeText(array) {
// 	if (typeof TextDecoder !== 'undefined') {
// 		return new TextDecoder().decode(array);
// 	}
// 	// Avoid the String.fromCharCode.apply(null, array) shortcut, which
// 	// throws a "maximum call stack size exceeded" error for large arrays.
// 	var s = '';
// 	for (var i = 0, il = array.length; i < il; i++) {
// 		// Implicitly assumes little-endian.
// 		s += String.fromCharCode(array[i]);
// 	}
// 	// Merges multi-byte utf-8 characters.
// 	return decodeURIComponent(escape(s));
// }
function GLTFBinaryExtension(data) {
    this.name = EXTENSIONS.KHR_BINARY_GLTF;
    this.content = null;
    this.body = null;
    var headerView = new DataView(data, 0, BINARY_EXTENSION_HEADER_LENGTH);
    this.header = {
        magic: decodeText(new Uint8Array(data.slice(0, 4))),
        version: headerView.getUint32(4, true),
        length: headerView.getUint32(8, true)
    };
    if (this.header.magic !== BINARY_EXTENSION_HEADER_MAGIC) {
        throw new Error('GLTFLoader: Unsupported glTF-Binary header.');
    }
    else if (this.header.version < 2.0) {
        throw new Error('GLTFLoader: Legacy binary file detected. Use LegacyGLTFLoader instead.');
    }
    var chunkView = new DataView(data, BINARY_EXTENSION_HEADER_LENGTH);
    var chunkIndex = 0;
    while (chunkIndex < chunkView.byteLength) {
        var chunkLength = chunkView.getUint32(chunkIndex, true);
        chunkIndex += 4;
        var chunkType = chunkView.getUint32(chunkIndex, true);
        chunkIndex += 4;
        if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.JSON) {
            var contentArray = new Uint8Array(data, BINARY_EXTENSION_HEADER_LENGTH + chunkIndex, chunkLength);
            this.content = decodeText(contentArray);
        }
        else if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.BIN) {
            var byteOffset = BINARY_EXTENSION_HEADER_LENGTH + chunkIndex;
            this.body = data.slice(byteOffset, byteOffset + chunkLength);
        }
        // Clients must ignore chunks with unknown types.
        chunkIndex += chunkLength;
    }
    if (this.content === null) {
        throw new Error('GLTFLoader: JSON content not found.');
    }
}
/* UTILITY FUNCTIONS */
function resolveURL(url, path) {
    // Invalid URL
    if (typeof url !== 'string' || url === '')
        return '';
    // Absolute URL http://,https://,//
    if (/^(https?:)?\/\//i.test(url))
        return url;
    // Data URI
    if (/^data:.*,.*$/i.test(url))
        return url;
    // Blob URL
    if (/^blob:.*$/i.test(url))
        return url;
    // Relative URL
    return path + url;
}
//用统一的，不止一个地方要用
// function ArrayBufferToBase64(buff) {
// 	var alph =
// 		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
// 		enc = "",
// 		n,
// 		p,
// 		bits,
// 		d = new Uint8Array(buff);
// 	var len = buff.byteLength * 8;
// 	for (var offset = 0; offset < len; offset += 6) {
// 		n = (offset / 8) | 0;
// 		p = offset % 8;
// 		bits = ((d[n] || 0) << p) >> 2;
// 		if (p > 2) {
// 			bits |= (d[n + 1] || 0) >> (10 - p);
// 		}
// 		enc += alph.charAt(bits & 63);
// 	}
// 	enc += p == 4 ? "=" : p == 6 ? "==" : "";
// 	return enc;
// }
// class GLTFRegistry {
// 	private static objects = {}
// 	constructor() { }
// 	get(key: string) {
// 		return GLTFRegistry.objects[key];
// 	}
// 	add(key: string, object: any) {
// 		GLTFRegistry.objects[key] = object;
// 	}
// 	remove(key: string) {
// 		delete GLTFRegistry.objects[key];
// 	}
// 	removeAll() {
// 		GLTFRegistry.objects = {};
// 	}
// }
//改成只缓存自己一个praser的，否则多个模型加载会取错缓存
var GLTFRegistry = /** @class */ (function () {
    function GLTFRegistry() {
        this.objects = {};
    }
    GLTFRegistry.prototype.get = function (key) {
        return this.objects[key];
    };
    GLTFRegistry.prototype.add = function (key, object) {
        this.objects[key] = object;
    };
    GLTFRegistry.prototype.remove = function (key) {
        delete this.objects[key];
    };
    GLTFRegistry.prototype.removeAll = function () {
        this.objects = {};
    };
    return GLTFRegistry;
}());
//仿three的，暂时用于记录数据，到时自己的也这么用？onUpload以后再说
var BufferAttribute = /** @class */ (function () {
    /**
     *
     * @param array Int8Array,Uint8Array, Int16Array,Uint16Array,Uint32Array,Float32Array
     * @param itemSize 步长，比如位置是3
     * @param normalized
     */
    function BufferAttribute(array, itemSize, normalized) {
        if (normalized === void 0) { normalized = false; }
        this.array = array;
        this.itemSize = itemSize;
        this.normalized = normalized;
        if (Array.isArray(array)) {
            throw new TypeError('Array should be a Typed Array');
        }
        this.count = array !== undefined ? array.length / itemSize : 0;
    }
    /**
     * 重写覆盖
     * @param value 普通数组，或类型化数组
     * @param offset
     */
    BufferAttribute.prototype.set = function (value, offset) {
        if (offset === void 0) { offset = 0; }
        this.array.set(value, offset);
        return this;
    };
    /**
     * 重置数据
     * @param array
     */
    BufferAttribute.prototype.setArray = function (array) {
        if (Array.isArray(array)) {
            throw new TypeError('Array should be a Typed Array');
        }
        this.count = array !== undefined ? array.length / this.itemSize : 0;
        this.array = array;
        return this;
    };
    /**
     *
     * @param index 第几个点
     */
    BufferAttribute.prototype.getX = function (index) {
        return this.array[index * this.itemSize];
    };
    BufferAttribute.prototype.setX = function (index, x) {
        this.array[index * this.itemSize] = x;
        return this;
    };
    BufferAttribute.prototype.getY = function (index) {
        return this.array[index * this.itemSize + 1];
    };
    BufferAttribute.prototype.setY = function (index, y) {
        this.array[index * this.itemSize + 1] = y;
        return this;
    };
    BufferAttribute.prototype.getZ = function (index) {
        return this.array[index * this.itemSize + 2];
    };
    BufferAttribute.prototype.setZ = function (index, z) {
        this.array[index * this.itemSize + 2] = z;
        return this;
    };
    BufferAttribute.prototype.getW = function (index) {
        return this.array[index * this.itemSize + 3];
    };
    BufferAttribute.prototype.setW = function (index, w) {
        this.array[index * this.itemSize + 3] = w;
        return this;
    };
    BufferAttribute.prototype.setXY = function (index, x, y) {
        index *= this.itemSize;
        this.array[index + 0] = x;
        this.array[index + 1] = y;
        return this;
    };
    BufferAttribute.prototype.setXYZ = function (index, x, y, z) {
        index *= this.itemSize;
        this.array[index + 0] = x;
        this.array[index + 1] = y;
        this.array[index + 2] = z;
        return this;
    };
    BufferAttribute.prototype.setXYZW = function (index, x, y, z, w) {
        index *= this.itemSize;
        this.array[index + 0] = x;
        this.array[index + 1] = y;
        this.array[index + 2] = z;
        this.array[index + 3] = w;
        return this;
    };
    BufferAttribute.prototype.copy = function (source) {
        this.name = source.name;
        this.array = new source.array.constructor(source.array);
        this.itemSize = source.itemSize;
        this.count = source.count;
        this.normalized = source.normalized;
        return this;
    };
    BufferAttribute.prototype.clone = function () {
        return new BufferAttribute(this.array, this.itemSize).copy(this);
    };
    return BufferAttribute;
}());
var InterleavedBuffer = /** @class */ (function () {
    function InterleavedBuffer(array, stride) {
        this.array = array;
        this.stride = stride;
        this.count = array !== undefined ? array.length / stride : 0;
    }
    InterleavedBuffer.prototype.setArray = function (array) {
        if (Array.isArray(array)) {
            throw new TypeError('Array should be a Typed Array.');
        }
        this.count = array !== undefined ? array.length / this.stride : 0;
        this.array = array;
        return this;
    };
    InterleavedBuffer.prototype.copy = function (source) {
        this.array = new source.array.constructor(source.array);
        this.count = source.count;
        this.stride = source.stride;
        return this;
    };
    InterleavedBuffer.prototype.set = function (value, offset) {
        if (offset === void 0) { offset = 0; }
        this.array.set(value, offset);
        return this;
    };
    InterleavedBuffer.prototype.clone = function () {
        return new InterleavedBuffer().copy(this);
    };
    return InterleavedBuffer;
}());
//特殊用处，貌似不会感到几何里，临时用来解码数据用
var InterleavedBufferAttribute = /** @class */ (function () {
    function InterleavedBufferAttribute(interleavedBuffer, itemSize, offset, normalized) {
        if (normalized === void 0) { normalized = false; }
        this.itemSize = itemSize;
        this.offset = offset;
        this.normalized = normalized;
        this.isInterleavedBufferAttribute = true;
        this.data = interleavedBuffer;
    }
    Object.defineProperty(InterleavedBufferAttribute.prototype, "count", {
        get: function () {
            return this.data.count;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(InterleavedBufferAttribute.prototype, "array", {
        get: function () {
            return this.data.array;
        },
        enumerable: false,
        configurable: true
    });
    InterleavedBufferAttribute.prototype.setX = function (index, x) {
        this.data.array[index * this.data.stride + this.offset] = x;
        return this;
    };
    InterleavedBufferAttribute.prototype.setY = function (index, y) {
        this.data.array[index * this.data.stride + this.offset + 1] = y;
        return this;
    };
    InterleavedBufferAttribute.prototype.setZ = function (index, z) {
        this.data.array[index * this.data.stride + this.offset + 2] = z;
        return this;
    };
    InterleavedBufferAttribute.prototype.setW = function (index, w) {
        this.data.array[index * this.data.stride + this.offset + 3] = w;
        return this;
    };
    InterleavedBufferAttribute.prototype.getX = function (index) {
        return this.data.array[index * this.data.stride + this.offset];
    };
    InterleavedBufferAttribute.prototype.getY = function (index) {
        return this.data.array[index * this.data.stride + this.offset + 1];
    };
    InterleavedBufferAttribute.prototype.getZ = function (index) {
        return this.data.array[index * this.data.stride + this.offset + 2];
    };
    InterleavedBufferAttribute.prototype.getW = function (index) {
        return this.data.array[index * this.data.stride + this.offset + 3];
    };
    InterleavedBufferAttribute.prototype.setXY = function (index, x, y) {
        index = index * this.data.stride + this.offset;
        this.data.array[index + 0] = x;
        this.data.array[index + 1] = y;
        return this;
    };
    InterleavedBufferAttribute.prototype.setXYZ = function (index, x, y, z) {
        index = index * this.data.stride + this.offset;
        this.data.array[index + 0] = x;
        this.data.array[index + 1] = y;
        this.data.array[index + 2] = z;
        return this;
    };
    InterleavedBufferAttribute.prototype.setXYZW = function (index, x, y, z, w) {
        index = index * this.data.stride + this.offset;
        this.data.array[index + 0] = x;
        this.data.array[index + 1] = y;
        this.data.array[index + 2] = z;
        this.data.array[index + 3] = w;
        return this;
    };
    return InterleavedBufferAttribute;
}());
//取出数组数据,位置法线都是3位,uv两位,截取位数
function attributeToArray(attr) {
    var arr = [];
    // var data: Float32Array = attr.array;
    for (var i = 0; i < attr.count; i++) {
        arr.push(attr.getX(i));
        if (attr.itemSize >= 2)
            arr.push(attr.getY(i));
        if (attr.itemSize >= 3)
            arr.push(attr.getZ(i));
        if (attr.itemSize >= 4)
            arr.push(attr.getW(i));
    }
    return arr;
}
var reservedRe = new RegExp('[' + '\\[\\]\\.:\\/' + ']', 'g');
function sanitizeNodeName(name) {
    return name.replace(/\s/g, '_').replace(reservedRe, '');
}
/**
 * 深度递归处理Object3D
 * @param object
 * @param callback
 */
function traverse(object, callback) {
    callback(object);
    var children = object.children;
    for (var i = 0, l = children.length; i < l; i++) {
        var c = children[i];
        traverse(c, callback);
    }
}

//所有sprite公用一个几何
var geometrySpirte3D;
var Sprite3D = /** @class */ (function (_super) {
    __extends(Sprite3D, _super);
    function Sprite3D(material) {
        var _this = this;
        if (!geometrySpirte3D) {
            var vertices = [
                -0.5, -0.5, 0,
                0.5, -0.5, 0,
                0.5, 0.5, 0,
                -0.5, 0.5, 0,
            ];
            var uvs = [
                0, 1,
                1, 1,
                1, 0,
                0, 0
            ];
            geometrySpirte3D = new Geometry(vertices, [0, 1, 2, 0, 2, 3], null, null, uvs);
        }
        //@ts-ignore
        _this = _super.call(this, geometrySpirte3D, material) || this;
        return _this;
    }
    return Sprite3D;
}(Mesh3D));

/**
 * 仿照three，用节点模拟，然后取全局矩阵，再赋值给显示对象
 */
var Bone = /** @class */ (function (_super) {
    __extends(Bone, _super); /*Container*/
    function Bone(data, root) {
        var _this = _super.call(this) || this;
        _this.data = data;
        _this.root = root;
        //a开头都是用于约束的，再说
        _this.ax = 0;
        _this.ay = 0;
        _this.arotation = 0;
        _this.ascaleX = 0;
        _this.ascaleY = 0;
        _this.ashearX = 0;
        _this.ashearY = 0;
        _this.appliedValid = false;
        _this.sorted = false;
        //不能用skew，因为是反的
        _this.shearX = 0;
        _this.shearY = 0;
        _this._instanceType = "Bone";
        _this.name = data.name;
        //考虑要不要处理下data
        _this.data.x = _this.data.x || 0;
        _this.data.y = _this.data.y || 0;
        _this.data.scaleX = _this.data.scaleX || 1;
        _this.data.scaleY = _this.data.scaleY || 1;
        _this.data.rotation = _this.data.rotation || 0;
        _this.data.shearX = _this.data.shearX || 0;
        _this.data.shearY = _this.data.shearY || 0;
        _this.setToSetupPose();
        //到时去掉
        if (root) {
            _this.debugBone = _this.addChild(new Graphics())
                .beginFill(0xff0000)
                .drawRect(0, 0, data.length || 10, 10)
                .endFill();
        }
        return _this;
    }
    Object.defineProperty(Bone.prototype, "matrix", {
        get: function () {
            return this.worldMatrix;
        },
        enumerable: false,
        configurable: true
    });
    Bone.prototype.setToSetupPose = function () {
        var data = this.data;
        this.x = data.x;
        this.y = data.y;
        this.rotation = data.rotation;
        this.scaleX = data.scaleX;
        this.scaleY = data.scaleY;
        this.shearX = data.shearX;
        this.shearY = data.shearY;
        //skew是反的
        this.skewX = -data.shearY;
        this.skewY = data.shearX;
    };
    //方式要改
    Bone.prototype.updateTransform = function () {
        this.appliedSelf();
        var sy = Bone.yDown ? -1 : 1;
        if (this.parent) {
            var parent = this.parent;
            if (this.parent.instanceType == "Bone") {
                // this.transform.updateLocalMatrix();//自己计算
                this.transform._worldID++;
                var pm = parent.transform.worldMatrix;
                var lm = this.localMatrix;
                var wm = this.worldMatrix;
                //pc和pb写错了，再说
                var pa = pm.a, pb = pm.c, pc = pm.b, pd = pm.d;
                wm.tx = pa * this.x + pb * this.y + pm.tx;
                wm.ty = pc * this.x + pd * this.y + pm.ty;
                //自身计算方式要根据data.transform
                switch (this.data.transform) {
                    case TransformType.onlyTranslation: //其他统统用lm的
                        this.transform.updateLocalMatrix();
                        wm.a = lm.a;
                        wm.c = lm.c;
                        wm.b = lm.b;
                        wm.d = lm.d;
                        break;
                    case TransformType.noRotationOrReflection: {
                        var s = pa * pa + pc * pc;
                        var prx = 0;
                        if (s > 0.0001) {
                            s = Math.abs(pa * pd - pb * pc) / s;
                            pb = pc * s;
                            pd = pa * s;
                            prx = Math.atan2(pc, pa) * RAD_TO_DEG;
                        }
                        else {
                            pa = 0;
                            pc = 0;
                            prx = 90 - Math.atan2(pd, pb) * RAD_TO_DEG;
                        }
                        var rx = this.rotation + this.shearX - prx;
                        var ry = this.rotation + this.shearY - prx + 90;
                        var la = Math.cos(rx * DEG_TO_RAD) * this.scaleX;
                        var lb = Math.cos(ry * DEG_TO_RAD) * this.scaleY * sy; //*sy反向，其他几种情况，遇到了再说
                        var lc = Math.sin(rx * DEG_TO_RAD) * this.scaleX;
                        var ld = Math.sin(ry * DEG_TO_RAD) * this.scaleY * sy;
                        wm.a = pa * la - pb * lc;
                        wm.c = pa * lb - pb * ld;
                        wm.b = pc * la + pd * lc;
                        wm.d = pc * lb + pd * ld;
                        break;
                    }
                    case TransformType.noScale:
                    case TransformType.noScaleOrReflection: {
                        var cos = Math.cos(this.rotation * DEG_TO_RAD);
                        var sin = Math.sin(this.rotation * DEG_TO_RAD);
                        var za = (pa * cos + pb * sin) / 1; //sx;
                        var zc = (pc * cos + pd * sin) / 1; //sy;
                        var s = Math.sqrt(za * za + zc * zc);
                        if (s > 0.00001)
                            s = 1 / s;
                        za *= s;
                        zc *= s;
                        s = Math.sqrt(za * za + zc * zc);
                        if (this.data.transform == TransformType.noScale
                            && (pa * pd - pb * pc < 0) != (Bone.yDown ?
                                // (this.skeleton.scaleX < 0 != this.skeleton.scaleY > 0) :
                                // (this.skeleton.scaleX < 0 != this.skeleton.scaleY < 0)))
                                (1 < 0 != -1 > 0) :
                                (1 < 0 != -1 < 0))) //先直接设置了
                            s = -s;
                        var r = Math.PI / 2 + Math.atan2(zc, za);
                        var zb = Math.cos(r) * s;
                        var zd = Math.sin(r) * s;
                        var la = Math.cos(this.shearX * DEG_TO_RAD) * this.scaleX;
                        var lb = Math.cos((90 + this.shearY) * DEG_TO_RAD) * this.scaleY;
                        var lc = Math.sin(this.shearX * DEG_TO_RAD) * this.scaleX;
                        var ld = Math.sin((90 + this.shearY) * DEG_TO_RAD) * this.scaleY;
                        wm.a = za * la + zb * lc;
                        wm.c = za * lb + zb * ld;
                        wm.b = zc * la + zd * lc;
                        wm.d = zc * lb + zd * ld;
                        break;
                    }
                    case TransformType.normal:
                    default:
                        // super.updateTransform();
                        // this.transform.updateWorldMatrix(this.parent.transform);
                        this.displayObjectUpdateTransform();
                        //下面这个官网的
                        // var rotation = this.rotation
                        // var rotationY = rotation + 90 + this.shearY;
                        // var la = Math.cos((rotation + this.shearX) * DEG_TO_RAD) * this.scaleX;
                        // var lb = Math.cos(rotationY * DEG_TO_RAD) * this.scaleY;
                        // var lc = Math.sin((rotation + this.shearX) * DEG_TO_RAD) * this.scaleX;
                        // var ld = Math.sin(rotationY * DEG_TO_RAD) * this.scaleY;
                        // wm.a = pa * la + pb * lc;
                        // wm.c = pa * lb + pb * ld;
                        // wm.b = pc * la + pd * lc;
                        // wm.d = pc * lb + pd * ld;
                        break;
                }
            }
            else {
                // super.updateTransform();
                //不能根据父级的来玩，把自己当作root
                var temp = this.parent;
                //@ts-ignore
                this.parent = this._tempDisplayObjectParent;
                this.transform.updateWorldMatrix(this.parent.transform);
                this.parent = temp;
            }
        }
        //子级
        for (var i = 0, j = this.children.length; i < j; ++i) {
            var child = this.children[i];
            child.updateTransform();
            if (child == this.debugBone) {
                //还需要root转一次
                child.worldMatrix.prepend(this.root.worldMatrix);
            }
        }
    };
    /**
     * 是parent的需要进行子级的递归，因为子级的在后执行
     * 这些都是最后执行的，直接修改自己的世界矩阵数据
     * @param x
     * @param y
     * @param rotation
     * @param scaleX
     * @param scaleY
     * @param shearX
     * @param shearY
     */
    Bone.prototype.updateWorldTransformWith = function (x, y, rotation, scaleX, scaleY, shearX, shearY) {
        this.ax = this.x = x;
        this.ay = this.y = y;
        this.arotation = this.rotation = rotation;
        this.ascaleX = this.scaleX = scaleX;
        this.ascaleY = this.scaleY = scaleY;
        this.ashearX = shearX;
        this.ashearY = shearY;
        this.appliedValid = true;
        //反的
        this.skewX = -shearY;
        this.skewY = shearX;
        //继续执行一边
        this.updateTransform();
    };
    Bone.prototype.appliedSelf = function () {
        this.ax = this.x;
        this.ay = this.y;
        this.arotation = this.rotation;
        this.ascaleX = this.scaleX;
        this.ascaleY = this.scaleY;
        this.ashearX = this.shearX; //this.skewX;
        this.ashearY = this.shearY; //this.skewY;
        this.appliedValid = true;
    };
    Bone.yDown = true; //当前引擎y轴朝下
    return Bone;
}(Container /*Container*/));
var TransformType;
(function (TransformType) {
    // normal = 0,//默认
    // onlyTranslation,
    // noRotationOrReflection,
    // noScale,
    // noScaleOrReflection,
    TransformType["normal"] = "normal";
    TransformType["onlyTranslation"] = "onlyTranslation";
    TransformType["noRotationOrReflection"] = "noRotationOrReflection";
    TransformType["noScale"] = "noScale";
    TransformType["noScaleOrReflection"] = "noScaleOrReflection";
})(TransformType || (TransformType = {}));

var SpineColor = /** @class */ (function () {
    function SpineColor(r, g, b, a) {
        if (r === void 0) { r = 0; }
        if (g === void 0) { g = 0; }
        if (b === void 0) { b = 0; }
        if (a === void 0) { a = 0; }
        this.r = r;
        this.g = g;
        this.b = b;
        this.a = a;
    }
    SpineColor.prototype.set = function (r, g, b, a) {
        this.r = r;
        this.g = g;
        this.b = b;
        this.a = a;
        this.clamp();
        return this;
    };
    SpineColor.prototype.setFromColor = function (c) {
        this.r = c.r;
        this.g = c.g;
        this.b = c.b;
        this.a = c.a;
        return this;
    };
    SpineColor.prototype.setFromString = function (hex) {
        hex = hex.charAt(0) == '#' ? hex.substr(1) : hex;
        this.r = parseInt(hex.substr(0, 2), 16) / 255.0;
        this.g = parseInt(hex.substr(2, 2), 16) / 255.0;
        this.b = parseInt(hex.substr(4, 2), 16) / 255.0;
        this.a = (hex.length != 8 ? 255 : parseInt(hex.substr(6, 2), 16)) / 255.0;
        return this;
    };
    SpineColor.prototype.add = function (r, g, b, a) {
        this.r += r;
        this.g += g;
        this.b += b;
        this.a += a;
        this.clamp();
        return this;
    };
    SpineColor.prototype.clamp = function () {
        if (this.r < 0)
            this.r = 0;
        else if (this.r > 1)
            this.r = 1;
        if (this.g < 0)
            this.g = 0;
        else if (this.g > 1)
            this.g = 1;
        if (this.b < 0)
            this.b = 0;
        else if (this.b > 1)
            this.b = 1;
        if (this.a < 0)
            this.a = 0;
        else if (this.a > 1)
            this.a = 1;
        return this;
    };
    SpineColor.fromString = function (hex) {
        return new SpineColor().setFromString(hex);
    };
    SpineColor.WHITE = new SpineColor(1, 1, 1, 1);
    SpineColor.RED = new SpineColor(1, 0, 0, 1);
    SpineColor.GREEN = new SpineColor(0, 1, 0, 1);
    SpineColor.BLUE = new SpineColor(0, 0, 1, 1);
    SpineColor.MAGENTA = new SpineColor(1, 0, 1, 1);
    return SpineColor;
}());

//作为插槽容器
//外部控制子级的加入及显示隐藏
var Slot = /** @class */ (function (_super) {
    __extends(Slot, _super);
    //讲道理原始数据都应该放进data
    // public originAttachment: Attachment;
    function Slot(
    /**
     * 绑定的骨骼
     */
    bone, 
    /**
     * 数据，用于恢复初始状态
     */
    data, spine) {
        var _this = _super.call(this) || this;
        _this.bone = bone;
        _this.data = data;
        _this.spine = spine;
        _this.deform = new Array(); //attachmentVertices
        _this.name = _this.data.name;
        _this.color = new SpineColor(1, 1, 1, 1);
        if (_this.data.color)
            _this.color.setFromString(_this.data.color);
        // 数据里的也加一个，不然实时转换性能差
        _this.data.sColor = new SpineColor().setFromColor(_this.color);
        return _this;
    }
    //重写，根据自己的bone的世界矩阵
    // updateTransform() {
    //     if (!this.visible) return;
    //     this.worldMatrix.setFrom(this.bone.worldMatrix);
    //     this.transform._worldID++;
    //     // 子级attachment
    //     for (var i = 0; i < this.children.length; i++) {
    //         this.children[i].updateTransform();
    //     }
    // }
    Slot.prototype.getAttachment = function () {
        return this.attachment;
    };
    Slot.prototype.setAttachment = function (attachment) {
        if (this.attachment == attachment)
            return;
        this.attachment = attachment;
        this.deform.length = 0;
    };
    //不再动画轨上执行，有需要自行执行
    Slot.prototype.setToSetupPose = function () {
        this.color.setFromColor(this.data.sColor);
        if (this.data.attachment == null)
            this.attachment = null;
        else {
            this.attachment = null;
            this.setAttachment(this.spine.getAttachment(this.spine["findSlotIndex"](this.name), this.data.attachment));
        }
    };
    return Slot;
}(Container));

var Skin = /** @class */ (function () {
    function Skin(name) {
        this.name = name;
        this.attachments = new Array();
    }
    Skin.prototype.addAttachment = function (slotIndex, name, attachment) {
        var attachments = this.attachments;
        if (slotIndex >= attachments.length)
            attachments.length = slotIndex + 1;
        if (!attachments[slotIndex])
            attachments[slotIndex] = {};
        attachments[slotIndex][name] = attachment;
    };
    Skin.prototype.getAttachment = function (slotIndex, name) {
        var dictionary = this.attachments[slotIndex];
        return dictionary ? dictionary[name] : null;
    };
    Skin.prototype.attachAll = function (slots, oldSkin) {
        var slotIndex = 0;
        for (var i = 0; i < slots.length; i++) {
            var slot = slots[i];
            var slotAttachment = slot.getAttachment();
            if (slotAttachment && slotIndex < oldSkin.attachments.length) {
                var dictionary = oldSkin.attachments[slotIndex];
                for (var key in dictionary) {
                    var skinAttachment = dictionary[key];
                    if (slotAttachment == skinAttachment) {
                        var attachment = this.getAttachment(slotIndex, key);
                        if (attachment != null)
                            slot.setAttachment(attachment);
                        break;
                    }
                }
            }
            slotIndex++;
        }
    };
    return Skin;
}());

//attachment用于记录数据用
var Attachment = /** @class */ (function () {
    function Attachment(name) {
        this.name = name;
    }
    return Attachment;
}());
var VertexAttachment = /** @class */ (function (_super) {
    __extends(VertexAttachment, _super);
    function VertexAttachment(name) {
        var _this = _super.call(this, name) || this;
        _this.id = (VertexAttachment.nextID++ & 65535) << 11;
        _this.worldVerticesLength = 0;
        _this.deformAttachment = _this;
        return _this;
    }
    VertexAttachment.prototype.applyDeform = function (sourceAttachment) {
        return this == sourceAttachment;
    };
    VertexAttachment.prototype.computeWorldVerticesOld = function (slot, worldVertices, skeletonBones) {
        this.computeWorldVertices(slot, 0, this.worldVerticesLength, worldVertices, 0, 2, skeletonBones);
    };
    /** Transforms local vertices to world coordinates.
     * @param start The index of the first local vertex value to transform. Each vertex has 2 values, x and y.
     * @param count The number of world vertex values to output. Must be <= {@link #getWorldVerticesLength()} - start.
     * @param worldVertices The output world vertices. Must have a length >= offset + count.
     * @param offset The worldVertices index to begin writing values. */
    VertexAttachment.prototype.computeWorldVertices = function (slot, start, count, worldVertices, offset, stride, skeletonBones //全部的骨骼数组
    ) {
        count = offset + (count >> 1) * stride;
        var deformArray = slot.deform;
        var vertices = this.vertices;
        var bones = this.bones;
        if (bones == null) {
            if (deformArray.length > 0)
                vertices = deformArray;
            var mat = slot.bone.matrix; //.worldMatrix;
            var x = mat.tx;
            var y = mat.ty;
            var a = mat.a, b = mat.c, c = mat.b, d = mat.d;
            for (var v_1 = start, w = offset; w < count; v_1 += 2, w += stride) {
                var vx = vertices[v_1], vy = vertices[v_1 + 1];
                //@ts-ignore
                worldVertices[w] = vx * a + vy * b + x;
                //@ts-ignore
                worldVertices[w + 1] = vx * c + vy * d + y;
            }
            return;
        }
        var v = 0, skip = 0;
        for (var i = 0; i < start; i += 2) {
            var n = bones[v];
            v += n + 1;
            skip += n;
        }
        if (deformArray.length == 0) {
            for (var w = offset, b = skip * 3; w < count; w += stride) {
                var wx = 0, wy = 0;
                var n = bones[v++];
                n += v;
                for (; v < n; v++, b += 3) {
                    var mat = skeletonBones[bones[v]].matrix; //.worldMatrix;
                    var vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2];
                    wx += (vx * mat.a + vy * mat.c + mat.tx) * weight;
                    wy += (vx * mat.b + vy * mat.d + mat.ty) * weight;
                }
                //@ts-ignore
                worldVertices[w] = wx;
                //@ts-ignore
                worldVertices[w + 1] = wy;
            }
        }
        else {
            var deform = deformArray;
            for (var w = offset, b = skip * 3, f = skip << 1; w < count; w += stride) {
                var wx = 0, wy = 0;
                var n = bones[v++];
                n += v;
                for (; v < n; v++, b += 3, f += 2) {
                    var mat = skeletonBones[bones[v]].matrix; //.worldMatrix;
                    var vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2];
                    wx += (vx * mat.a + vy * mat.c + mat.tx) * weight;
                    wy += (vx * mat.b + vy * mat.d + mat.ty) * weight;
                }
                //@ts-ignore
                worldVertices[w] = wx;
                //@ts-ignore
                worldVertices[w + 1] = wy;
            }
        }
    };
    VertexAttachment.nextID = 0;
    return VertexAttachment;
}(Attachment));

var RegionAttachment = /** @class */ (function (_super) {
    __extends(RegionAttachment, _super);
    function RegionAttachment(name, x, y, scaleX, scaleY, rotation, width, height, 
    //应用的纹理
    texture) {
        if (x === void 0) { x = 0; }
        if (y === void 0) { y = 0; }
        if (scaleX === void 0) { scaleX = 1; }
        if (scaleY === void 0) { scaleY = 1; }
        if (rotation === void 0) { rotation = 0; }
        if (width === void 0) { width = 0; }
        if (height === void 0) { height = 0; }
        var _this = _super.call(this, name) || this;
        _this.x = x;
        _this.y = y;
        _this.scaleX = scaleX;
        _this.scaleY = scaleY;
        _this.rotation = rotation;
        _this.width = width;
        _this.height = height;
        _this.texture = texture;
        _this.color = new SpineColor(1, 1, 1, 1);
        return _this;
    }
    return RegionAttachment;
}(Attachment));

var MeshAttachment = /** @class */ (function (_super) {
    __extends(MeshAttachment, _super);
    function MeshAttachment() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        _this.color = new SpineColor(1, 1, 1, 1);
        return _this;
    }
    return MeshAttachment;
}(VertexAttachment));

/**
 * 为了方便提前计算贝塞尔的补间
 */
var Curve = /** @class */ (function () {
    function Curve(frameCount) {
        this.curves = new Float32Array((frameCount - 1) * Curve.BEZIER_SIZE);
    }
    /** The number of key frames for this timeline. */
    Curve.prototype.getFrameCount = function () {
        return this.curves.length / Curve.BEZIER_SIZE + 1;
    };
    /** Sets the specified key frame to linear interpolation. */
    Curve.prototype.setLinear = function (frameIndex) {
        this.curves[frameIndex * Curve.BEZIER_SIZE] = Curve.LINEAR;
    };
    /** Sets the specified key frame to stepped interpolation. */
    Curve.prototype.setStepped = function (frameIndex) {
        this.curves[frameIndex * Curve.BEZIER_SIZE] = Curve.STEPPED;
    };
    /** Returns the interpolation type for the specified key frame.
     * @returns Linear is 0, stepped is 1, Bezier is 2. */
    Curve.prototype.getCurveType = function (frameIndex) {
        var index = frameIndex * Curve.BEZIER_SIZE;
        if (index == this.curves.length)
            return Curve.LINEAR;
        var type = this.curves[index];
        if (type == Curve.LINEAR)
            return Curve.LINEAR;
        if (type == Curve.STEPPED)
            return Curve.STEPPED;
        return Curve.BEZIER;
    };
    /** Sets the specified key frame to Bezier interpolation. `cx1` and `cx2` are from 0 to 1,
     * representing the percent of time between the two key frames. `cy1` and `cy2` are the percent of the
     * difference between the key frame's values. */
    Curve.prototype.setCurve = function (frameIndex, cx1, cy1, cx2, cy2) {
        var tmpx = (-cx1 * 2 + cx2) * 0.03, tmpy = (-cy1 * 2 + cy2) * 0.03;
        var dddfx = ((cx1 - cx2) * 3 + 1) * 0.006, dddfy = ((cy1 - cy2) * 3 + 1) * 0.006;
        var ddfx = tmpx * 2 + dddfx, ddfy = tmpy * 2 + dddfy;
        var dfx = cx1 * 0.3 + tmpx + dddfx * 0.16666667, dfy = cy1 * 0.3 + tmpy + dddfy * 0.16666667;
        var i = frameIndex * Curve.BEZIER_SIZE;
        var curves = this.curves;
        curves[i++] = Curve.BEZIER;
        var x = dfx, y = dfy;
        for (var n = i + Curve.BEZIER_SIZE - 1; i < n; i += 2) {
            curves[i] = x;
            curves[i + 1] = y;
            dfx += ddfx;
            dfy += ddfy;
            ddfx += dddfx;
            ddfy += dddfy;
            x += dfx;
            y += dfy;
        }
    };
    /** Returns the interpolated percentage for the specified key frame and linear percentage. */
    Curve.prototype.getCurvePercent = function (frameIndex, percent) {
        percent = clamp(percent, 0, 1);
        var curves = this.curves;
        var i = frameIndex * Curve.BEZIER_SIZE;
        var type = curves[i];
        if (type == Curve.LINEAR)
            return percent;
        if (type == Curve.STEPPED)
            return 0;
        i++;
        var x = 0;
        for (var start = i, n = i + Curve.BEZIER_SIZE - 1; i < n; i += 2) {
            x = curves[i];
            if (x >= percent) {
                var prevX = void 0, prevY = void 0;
                if (i == start) {
                    prevX = 0;
                    prevY = 0;
                }
                else {
                    prevX = curves[i - 2];
                    prevY = curves[i - 1];
                }
                return prevY + (curves[i + 1] - prevY) * (percent - prevX) / (x - prevX);
            }
        }
        var y = curves[i - 1];
        return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1.
    };
    Curve.LINEAR = 0;
    Curve.STEPPED = 1;
    Curve.BEZIER = 2;
    Curve.BEZIER_SIZE = 10 * 2 - 1;
    return Curve;
}());
/**
 * 根据map的curve属性，给curve设置缓动方法
 * @param map
 * @param curve
 * @param frameIndex
 */
function readCurve(map, curve, frameIndex) {
    if (!map.hasOwnProperty("curve"))
        return;
    if (map.curve === "stepped")
        curve.setStepped(frameIndex);
    else if (Object.prototype.toString.call(map.curve) === '[object Array]') {
        var curveArr = map.curve;
        curve.setCurve(frameIndex, curveArr[0], curveArr[1], curveArr[2], curveArr[3]);
    }
    else { //兼容下
        curve.setCurve(frameIndex, map.curve, map.c2 || 0, map.c3 || 1, map.c4 || 1);
    }
}
var MixBlend;
(function (MixBlend) {
    MixBlend[MixBlend["setup"] = 0] = "setup";
    MixBlend[MixBlend["first"] = 1] = "first";
    MixBlend[MixBlend["replace"] = 2] = "replace";
    MixBlend[MixBlend["add"] = 3] = "add";
})(MixBlend || (MixBlend = {}));
//用于混合，暂时都是in
var MixDirection;
(function (MixDirection) {
    MixDirection[MixDirection["in"] = 0] = "in";
    MixDirection[MixDirection["out"] = 1] = "out";
})(MixDirection || (MixDirection = {}));
/**
 * 这种数组查找会快点，到时也可以缝一下，找最接近的下一个的索引
 * @param values
 * @param target
 */
function binarySearch$2(values, target, step) {
    if (step === void 0) { step = 1; }
    var low = 0;
    var high = values.length / step - 2;
    if (high == 0)
        return step;
    var current = high >>> 1;
    while (true) {
        if (values[(current + 1) * step] <= target)
            low = current + 1;
        else
            high = current;
        if (low == high)
            return (low + 1) * step;
        current = (low + high) >>> 1;
    }
}
function arrayCopy(source, sourceStart, dest, destStart, numElements) {
    for (var i = sourceStart, j = destStart; i < sourceStart + numElements; i++, j++) {
        dest[j] = source[i];
    }
}
function setArraySize(array, size, value) {
    if (value === void 0) { value = 0; }
    var oldSize = array.length;
    if (oldSize == size)
        return array;
    array.length = size;
    if (oldSize < size) {
        for (var i = oldSize; i < size; i++)
            array[i] = value;
    }
    return array;
}
function newArray(size, defaultValue) {
    var array = new Array(size);
    for (var i = 0; i < size; i++)
        array[i] = defaultValue;
    return array;
}

var BaseTrack = /** @class */ (function (_super) {
    __extends(BaseTrack, _super);
    function BaseTrack() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    //和原版少了lastTime，事件才用到
    BaseTrack.prototype.setValue = function (time, alpha, blend, direction) {
        if (blend === void 0) { blend = MixBlend.replace; }
        if (direction === void 0) { direction = MixDirection.in; }
    };
    BaseTrack.prototype.resetValue = function () {
    };
    BaseTrack.prototype.destroy = function () {
    };
    return BaseTrack;
}(HashObject));

var SpineBoneAniType;
(function (SpineBoneAniType) {
    //bone的
    SpineBoneAniType["rotate"] = "rotate";
    SpineBoneAniType["translate"] = "translate";
    SpineBoneAniType["scale"] = "scale";
    SpineBoneAniType["shear"] = "shear";
})(SpineBoneAniType || (SpineBoneAniType = {}));
var SpineBoneAniTrack = /** @class */ (function (_super) {
    __extends(SpineBoneAniTrack, _super);
    function SpineBoneAniTrack(
    /**
     * 需要改变属性的节点对象
     */
    bone, 
    /**
     * 动画类型
     */
    animationType, 
    /**
     * 记录所有时间的数组，按顺序递增，没有的按最后一个时间的数据
     */
    times) {
        var _this = _super.call(this) || this;
        _this.bone = bone;
        _this.animationType = animationType;
        _this.times = times;
        _this._instanceType = "SpineBoneAniTrack";
        times.forEach(function (t) {
            t.time = t.time || 0;
            switch (animationType) {
                case SpineBoneAniType.rotate:
                    t.angle = t.angle || 0;
                    break;
                case SpineBoneAniType.scale:
                    t.x = t.x === undefined ? 1 : t.x;
                    t.y = t.y === undefined ? 1 : t.y;
                    break;
                case SpineBoneAniType.translate:
                case SpineBoneAniType.shear:
                    t.x = t.x || 0;
                    t.y = t.y || 0;
                    break;
            }
        });
        //记录缓动
        _this.curve = new Curve(times.length);
        var frameIndex = 0;
        for (var i = 0; i < times.length; i++) {
            var map = times[i];
            readCurve(map, _this.curve, frameIndex);
            frameIndex++;
        }
        return _this;
    }
    SpineBoneAniTrack.prototype.resetValue = function () {
        this.bone.setToSetupPose();
    };
    /**
     * 传入时间设置对应的属性值，time大于所有动画总时间，外部处理   blend到时考虑要怎么传
     * @param time
     */
    // setValue1(time: number, mix: number = 1, blend: MixBlend = MixBlend.replace) {
    //     var value: number[] = this.getValue(time);//返回的是数组
    //     switch (this.animationType) {
    //         case SpineBoneAniType.translate:
    //             if (time < this.times[0].time) {
    //                 switch (blend) {
    //                     case MixBlend.setup:
    //                         this.bone.x = this.bone.data.x;
    //                         this.bone.y = this.bone.data.y;
    //                         break;
    //                     case MixBlend.first:
    //                         this.bone.x += (this.bone.data.x - this.bone.x) //* mix;
    //                         this.bone.y += (this.bone.data.y - this.bone.y) //* mix;
    //                         break;
    //                 }
    //             } else {
    //                 var x = value[0];
    //                 var y = value[1];
    //                 switch (blend) {
    //                     case MixBlend.setup:
    //                         this.bone.x = this.bone.data.x + x //* alpha;
    //                         this.bone.y = this.bone.data.y + y //* alpha;
    //                         break;
    //                     case MixBlend.first:
    //                     case MixBlend.replace:
    //                         this.bone.x += (this.bone.data.x + x - this.bone.x) //* alpha;
    //                         this.bone.y += (this.bone.data.y + y - this.bone.y) //* alpha;
    //                         break;
    //                     case MixBlend.add:
    //                         this.bone.x += x //* alpha;
    //                         this.bone.y += y //* alpha;
    //                 }
    //             }
    //             // this.node.position.set(value[0], value[1]);
    //             break;
    //         case SpineBoneAniType.scale:
    //             this.bone.scale.set(value[0], value[1]);
    //             break;
    //         case SpineBoneAniType.shear:
    //             this.bone.skewX = value[0];
    //             this.bone.skewY = value[1];
    //             break;
    //         case SpineBoneAniType.rotate:
    //             if (time < this.times[0].time) {
    //                 switch (blend) {
    //                     case MixBlend.setup:
    //                         this.bone.rotation = this.bone.data.rotation;
    //                         return;
    //                     case MixBlend.first:
    //                         var r_1 = this.bone.data.rotation - this.bone.rotation;
    //                         this.bone.rotation += (r_1 - (16384 - ((16384.499999999996 - r_1 / 360) | 0)) * 360) * 1//alpha;
    //                 }
    //             }
    //             else if (time >= this.times[this.times.length - 1].time) {
    //                 var r_2 = value[0]
    //                 switch (blend) {
    //                     case MixBlend.setup:
    //                         this.node.rotation = this.node.data.rotation + value[0] //* alpha;
    //                         break;
    //                     case MixBlend.first:
    //                     case MixBlend.replace:
    //                         r_2 += this.node.data.rotation - this.node.rotation;
    //                         this.node.rotation -= (16384 - ((16384.499999999996 - r_2 / 360) | 0)) * 360;
    //                     case MixBlend.add:
    //                         this.node.rotation += r_2 //* alpha;
    //                 }
    //             } else {
    //                 var r = value[0];
    //                 switch (blend) {
    //                     case MixBlend.setup:
    //                         this.bone.rotation = this.bone.data.rotation + (r - (16384 - ((16384.499999999996 - r / 360) | 0)) * 360) //* alpha;
    //                         break;
    //                     case MixBlend.first:
    //                     case MixBlend.replace:
    //                         r += this.bone.data.rotation - this.bone.rotation;
    //                     case MixBlend.add:
    //                         this.bone.rotation += (r - (16384 - ((16384.499999999996 - r / 360) | 0)) * 360) //* alpha;
    //                 }
    //             }
    //             break;
    //     }
    // }
    SpineBoneAniTrack.prototype.setValue = function (time, alpha, blend, direction) {
        if (alpha === void 0) { alpha = 1; }
        if (blend === void 0) { blend = MixBlend.replace; }
        if (direction === void 0) { direction = MixDirection.in; }
        switch (this.animationType) {
            case SpineBoneAniType.translate:
                this.setPosition(time, alpha, blend);
                break;
            case SpineBoneAniType.scale:
                this.setScale(time, alpha, blend, direction);
                break;
            case SpineBoneAniType.shear:
                this.setShear(time, alpha, blend);
                break;
            case SpineBoneAniType.rotate:
                this.setRotation(time, alpha, blend);
                break;
        }
    };
    SpineBoneAniTrack.prototype.setRotation = function (time, alpha, blend) {
        if (alpha === void 0) { alpha = 1; }
        if (blend === void 0) { blend = MixBlend.replace; }
        var frames = this.times;
        var bone = this.bone;
        if (time < frames[0].time) {
            switch (blend) {
                case MixBlend.setup:
                    bone.rotation = bone.data.rotation;
                    return;
                case MixBlend.first:
                    var r_1 = bone.data.rotation - bone.rotation;
                    bone.rotation += (r_1 - transRotation(r_1)) * alpha;
            }
            return;
        }
        if (time >= frames[frames.length - 1].time) {
            var r_2 = frames[frames.length - 1].angle;
            switch (blend) {
                case MixBlend.setup:
                    bone.rotation = bone.data.rotation + r_2 * alpha;
                    break;
                case MixBlend.first:
                case MixBlend.replace:
                    r_2 += bone.data.rotation - bone.rotation;
                    r_2 -= transRotation(r_2);
                case MixBlend.add:
                    bone.rotation += r_2 * alpha;
            }
            return;
        }
        var frame = this.findPreIndex(time);
        var prevRotation = frames[frame - 1].angle;
        var frameTime = frames[frame].time;
        var percent = this.curve.getCurvePercent(frame - 1, 1 - (time - frameTime) / (frames[frame - 1].time - frameTime));
        var r = frames[frame].angle - prevRotation;
        r = prevRotation + (r - transRotation(r)) * percent;
        switch (blend) {
            case MixBlend.setup:
                bone.rotation = bone.data.rotation + (r - transRotation(r)) * alpha;
                break;
            case MixBlend.first:
            case MixBlend.replace:
                r += bone.data.rotation - bone.rotation;
            case MixBlend.add:
                bone.rotation += (r - transRotation(r)) * alpha;
        }
    };
    SpineBoneAniTrack.prototype.setPosition = function (time, alpha, blend) {
        if (alpha === void 0) { alpha = 1; }
        if (blend === void 0) { blend = MixBlend.replace; }
        var frames = this.times;
        var bone = this.bone;
        if (time < frames[0].time) {
            switch (blend) {
                case MixBlend.setup:
                    bone.x = bone.data.x;
                    bone.y = bone.data.y;
                    return;
                case MixBlend.first:
                    bone.x += (bone.data.x - bone.x) * alpha;
                    bone.y += (bone.data.y - bone.y) * alpha;
            }
            return;
        }
        var x = 0, y = 0;
        if (time >= frames[frames.length - 1].time) {
            x = frames[frames.length - 1].x;
            y = frames[frames.length - 1].y;
        }
        else {
            var frame = this.findPreIndex(time);
            x = frames[frame - 1].x;
            y = frames[frame - 1].y;
            var frameTime = frames[frame].time;
            var percent = this.curve.getCurvePercent(frame - 1, 1 - (time - frameTime) / (frames[frame - 1].time - frameTime));
            x += (frames[frame].x - x) * percent;
            y += (frames[frame].y - y) * percent;
        }
        switch (blend) {
            case MixBlend.setup:
                bone.x = bone.data.x + x * alpha;
                bone.y = bone.data.y + y * alpha;
                break;
            case MixBlend.first:
            case MixBlend.replace:
                bone.x += (bone.data.x + x - bone.x) * alpha;
                bone.y += (bone.data.y + y - bone.y) * alpha;
                break;
            case MixBlend.add:
                bone.x += x * alpha;
                bone.y += y * alpha;
        }
    };
    SpineBoneAniTrack.prototype.setScale = function (time, alpha, blend, direction) {
        if (alpha === void 0) { alpha = 1; }
        if (blend === void 0) { blend = MixBlend.replace; }
        if (direction === void 0) { direction = MixDirection.in; }
        var frames = this.times;
        var bone = this.bone;
        if (time < frames[0].time) {
            switch (blend) {
                case MixBlend.setup:
                    bone.scaleX = bone.data.scaleX;
                    bone.scaleY = bone.data.scaleY;
                    return;
                case MixBlend.first:
                    bone.scaleX += (bone.data.scaleX - bone.scaleX) * alpha;
                    bone.scaleY += (bone.data.scaleY - bone.scaleY) * alpha;
            }
            return;
        }
        var x = 0, y = 0;
        if (time >= frames[frames.length - 1].time) {
            x = frames[frames.length - 1].x * bone.data.scaleX;
            y = frames[frames.length - 1].y * bone.data.scaleY;
        }
        else {
            var frame = this.findPreIndex(time);
            x = frames[frame - 1].x;
            y = frames[frame - 1].y;
            var frameTime = frames[frame].time;
            var percent = this.curve.getCurvePercent(frame - 1, 1 - (time - frameTime) / (frames[frame - 1].time - frameTime));
            x = (x + (frames[frame].x - x) * percent) * bone.data.scaleX;
            y = (y + (frames[frame].y - y) * percent) * bone.data.scaleY;
        }
        if (alpha == 1) {
            if (blend == MixBlend.add) {
                bone.scaleX += x - bone.data.scaleX;
                bone.scaleY += y - bone.data.scaleY;
            }
            else {
                bone.scaleX = x;
                bone.scaleY = y;
            }
        }
        else {
            var bx = 0, by = 0;
            if (direction == MixDirection.out) {
                switch (blend) {
                    case MixBlend.setup:
                        bx = bone.data.scaleX;
                        by = bone.data.scaleY;
                        bone.scaleX = bx + (Math.abs(x) * sign(bx) - bx) * alpha;
                        bone.scaleY = by + (Math.abs(y) * sign(by) - by) * alpha;
                        break;
                    case MixBlend.first:
                    case MixBlend.replace:
                        bx = bone.scaleX;
                        by = bone.scaleY;
                        bone.scaleX = bx + (Math.abs(x) * sign(bx) - bx) * alpha;
                        bone.scaleY = by + (Math.abs(y) * sign(by) - by) * alpha;
                        break;
                    case MixBlend.add:
                        bx = bone.scaleX;
                        by = bone.scaleY;
                        bone.scaleX = bx + (Math.abs(x) * sign(bx) - bone.data.scaleX) * alpha;
                        bone.scaleY = by + (Math.abs(y) * sign(by) - bone.data.scaleY) * alpha;
                }
            }
            else {
                switch (blend) {
                    case MixBlend.setup:
                        bx = Math.abs(bone.data.scaleX) * sign(x);
                        by = Math.abs(bone.data.scaleY) * sign(y);
                        bone.scaleX = bx + (x - bx) * alpha;
                        bone.scaleY = by + (y - by) * alpha;
                        break;
                    case MixBlend.first:
                    case MixBlend.replace:
                        bx = Math.abs(bone.scaleX) * sign(x);
                        by = Math.abs(bone.scaleY) * sign(y);
                        bone.scaleX = bx + (x - bx) * alpha;
                        bone.scaleY = by + (y - by) * alpha;
                        break;
                    case MixBlend.add:
                        bx = sign(x);
                        by = sign(y);
                        bone.scaleX = Math.abs(bone.scaleX) * bx + (x - Math.abs(bone.data.scaleX) * bx) * alpha;
                        bone.scaleY = Math.abs(bone.scaleY) * by + (y - Math.abs(bone.data.scaleY) * by) * alpha;
                }
            }
        }
    };
    SpineBoneAniTrack.prototype.setShear = function (time, alpha, blend) {
        if (alpha === void 0) { alpha = 1; }
        if (blend === void 0) { blend = MixBlend.replace; }
        var frames = this.times;
        var bone = this.bone;
        if (time < frames[0].time) {
            switch (blend) {
                case MixBlend.setup:
                    bone.shearX = bone.data.shearX;
                    bone.shearY = bone.data.shearY;
                    //反的
                    bone.skewX = -bone.shearY;
                    bone.skewY = bone.shearX;
                    return;
                case MixBlend.first:
                    bone.shearX += (bone.data.shearX - bone.shearX) * alpha;
                    bone.shearY += (bone.data.shearY - bone.shearY) * alpha;
                    //反的
                    bone.skewX = -bone.shearY;
                    bone.skewY = bone.shearX;
            }
            return;
        }
        var x = 0, y = 0;
        if (time >= frames[frames.length - 1].time) {
            x = frames[frames.length - 1].x;
            y = frames[frames.length - 1].y;
        }
        else {
            var frame = this.findPreIndex(time);
            x = frames[frame - 1].x;
            y = frames[frame - 1].y;
            var frameTime = frames[frame].time;
            var percent = this.curve.getCurvePercent(frame - 1, 1 - (time - frameTime) / (frames[frame - 1].time - frameTime));
            x = x + (frames[frame].x - x) * percent;
            y = y + (frames[frame].y - y) * percent;
        }
        switch (blend) {
            case MixBlend.setup:
                bone.shearX = bone.data.shearX + x * alpha;
                bone.shearY = bone.data.shearY + y * alpha;
                break;
            case MixBlend.first:
            case MixBlend.replace:
                bone.shearX += (bone.data.shearX + x - bone.shearX) * alpha;
                bone.shearY += (bone.data.shearY + y - bone.shearY) * alpha;
                break;
            case MixBlend.add:
                bone.shearX += x * alpha;
                bone.shearY += y * alpha;
        }
        //反的
        bone.skewX = -bone.shearY;
        bone.skewY = bone.shearX;
    };
    /**
     * 外部已经剔除了第一帧和最后一帧。到时试试二元法，估计更快点
     * @param time
     */
    SpineBoneAniTrack.prototype.findPreIndex = function (time) {
        var lastIndex = 0;
        for (var i = 0; i < this.times.length; i++) {
            if (this.times[i].time > time) {
                lastIndex = i;
                break;
            }
        }
        return lastIndex;
    };
    SpineBoneAniTrack.prototype.destroy = function () {
        this.bone = null;
        this.times = null;
    };
    return SpineBoneAniTrack;
}(BaseTrack));
function transRotation(r) {
    return (16384 - ((16384.499999999996 - r / 360) | 0)) * 360;
}

var SpineColorAniTrack = /** @class */ (function (_super) {
    __extends(SpineColorAniTrack, _super);
    function SpineColorAniTrack(
    /**
     * 需要改变颜色的插槽
     */
    slot, 
    /**
     * 改一下到时记录进frams数组
     */
    times) {
        var _this = _super.call(this) || this;
        _this.slot = slot;
        _this._instanceType = "SpineColorAniTrack";
        var len = times.length;
        _this.frames = new Float32Array(len * SpineColorAniTrack.ENTRIES);
        _this.curve = new Curve(len);
        var frameIndex = 0;
        for (var i = 0; i < len; i++) {
            var valueMap = times[i];
            var color = new SpineColor().setFromString(valueMap.color || "ffffffff");
            var fi = frameIndex * SpineColorAniTrack.ENTRIES;
            _this.frames[fi] = valueMap.time || 0;
            _this.frames[fi + SpineColorAniTrack.R] = color.r;
            _this.frames[fi + SpineColorAniTrack.G] = color.g;
            _this.frames[fi + SpineColorAniTrack.B] = color.b;
            _this.frames[fi + SpineColorAniTrack.A] = color.a;
            readCurve(valueMap, _this.curve, frameIndex);
            frameIndex++;
        }
        return _this;
    }
    SpineColorAniTrack.prototype.resetValue = function () {
        this.slot.setToSetupPose();
    };
    SpineColorAniTrack.prototype.setValue = function (time, alpha, blend) {
        if (alpha === void 0) { alpha = 1; }
        if (blend === void 0) { blend = MixBlend.replace; }
        var slot = this.slot;
        var frames = this.frames;
        if (time < frames[0]) {
            switch (blend) {
                case MixBlend.setup:
                    slot.color.setFromColor(slot.data.sColor);
                    return;
                case MixBlend.first:
                case MixBlend.replace:
                    var color = slot.color, setup = slot.data.sColor;
                    color.add((setup.r - color.r) * alpha, (setup.g - color.g) * alpha, (setup.b - color.b) * alpha, (setup.a - color.a) * alpha);
            }
            return;
        }
        var r = 0, g = 0, b = 0, a = 0;
        if (time >= frames[frames.length - SpineColorAniTrack.ENTRIES]) {
            var i = frames.length;
            r = frames[i + SpineColorAniTrack.PREV_R];
            g = frames[i + SpineColorAniTrack.PREV_G];
            b = frames[i + SpineColorAniTrack.PREV_B];
            a = frames[i + SpineColorAniTrack.PREV_A];
        }
        else {
            var frame = binarySearch$2(frames, time, SpineColorAniTrack.ENTRIES);
            r = frames[frame + SpineColorAniTrack.PREV_R];
            g = frames[frame + SpineColorAniTrack.PREV_G];
            b = frames[frame + SpineColorAniTrack.PREV_B];
            a = frames[frame + SpineColorAniTrack.PREV_A];
            var frameTime = frames[frame];
            var percent = this.curve.getCurvePercent(frame / SpineColorAniTrack.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + SpineColorAniTrack.PREV_TIME] - frameTime));
            r += (frames[frame + SpineColorAniTrack.R] - r) * percent;
            g += (frames[frame + SpineColorAniTrack.G] - g) * percent;
            b += (frames[frame + SpineColorAniTrack.B] - b) * percent;
            a += (frames[frame + SpineColorAniTrack.A] - a) * percent;
        }
        if (alpha == 1)
            slot.color.set(r, g, b, a);
        else {
            var color = slot.color;
            if (blend == MixBlend.setup)
                color.setFromColor(slot.data.sColor);
            color.add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha);
        }
    };
    SpineColorAniTrack.ENTRIES = 5;
    SpineColorAniTrack.PREV_TIME = -5;
    SpineColorAniTrack.PREV_R = -4;
    SpineColorAniTrack.PREV_G = -3;
    SpineColorAniTrack.PREV_B = -2;
    SpineColorAniTrack.PREV_A = -1;
    SpineColorAniTrack.R = 1;
    SpineColorAniTrack.G = 2;
    SpineColorAniTrack.B = 3;
    SpineColorAniTrack.A = 4;
    return SpineColorAniTrack;
}(BaseTrack));

var SpineDeformAniTrack = /** @class */ (function (_super) {
    __extends(SpineDeformAniTrack, _super);
    function SpineDeformAniTrack(
    /**
     * 需要改变属性的节点对象
     */
    slot, 
    /**
     * 皮肤上获取的，slot可能不一致
     */
    attachment, 
    /**
     * 记录所有时间的数组，按顺序递增，没有的按最后一个时间的数据
     */
    times) {
        var _this = _super.call(this) || this;
        _this.slot = slot;
        _this.attachment = attachment;
        _this.times = times;
        _this._instanceType = "SpineDeformAniTrack";
        var weighted = attachment.bones != null;
        var vertices = attachment.vertices;
        var deformLength = weighted ? vertices.length / 3 * 2 : vertices.length;
        _this.frameTimes = new Float32Array(times.length);
        _this.frameVertices = new Array(times.length);
        _this.curve = new Curve(times.length);
        var frameIndex = 0;
        for (var j = 0; j < times.length; j++) {
            var valueMap = times[j];
            var deform = void 0;
            var verticesValue = valueMap.vertices || null;
            if (verticesValue == null)
                deform = weighted ? new Float32Array(deformLength) : vertices;
            else {
                deform = new Float32Array(deformLength);
                var start = valueMap.offset || 0;
                arrayCopy(verticesValue, 0, deform, start, verticesValue.length);
                if (!weighted) {
                    for (var i = 0; i < deformLength; i++)
                        deform[i] += vertices[i];
                }
            }
            // timeline.setFrame(frameIndex, valueMap.time, deform);
            _this.frameTimes[frameIndex] = valueMap.time || 0;
            _this.frameVertices[frameIndex] = deform;
            readCurve(valueMap, _this.curve, frameIndex);
            frameIndex++;
        }
        return _this;
    }
    //到时后两个参数直接赋值track吧
    SpineDeformAniTrack.prototype.setValue = function (time, alpha, blend) {
        if (alpha === void 0) { alpha = 1; }
        if (blend === void 0) { blend = MixBlend.replace; }
        var slotAttachment = this.slot.getAttachment();
        if (!(slotAttachment instanceof VertexAttachment) || !slotAttachment.applyDeform(this.attachment))
            return;
        var verticesArray = this.slot.deform;
        if (verticesArray.length == 0)
            blend = MixBlend.setup;
        var frameVertices = this.frameVertices;
        var vertexCount = frameVertices[0].length;
        var frames = this.frameTimes;
        if (time < frames[0]) {
            var vertexAttachment = slotAttachment;
            switch (blend) {
                case MixBlend.setup:
                    verticesArray.length = 0;
                    return;
                case MixBlend.first:
                    if (alpha == 1) {
                        verticesArray.length = 0;
                        break;
                    }
                    var vertices_1 = setArraySize(verticesArray, vertexCount);
                    if (vertexAttachment.bones == null) {
                        var setupVertices = vertexAttachment.vertices;
                        for (var i = 0; i < vertexCount; i++)
                            vertices_1[i] += (setupVertices[i] - vertices_1[i]) * alpha;
                    }
                    else {
                        alpha = 1 - alpha;
                        for (var i = 0; i < vertexCount; i++)
                            vertices_1[i] *= alpha;
                    }
            }
            return;
        }
        var vertices = setArraySize(verticesArray, vertexCount);
        if (time >= frames[frames.length - 1]) {
            var lastVertices = frameVertices[frames.length - 1];
            if (alpha == 1) {
                if (blend == MixBlend.add) {
                    var vertexAttachment = slotAttachment;
                    if (vertexAttachment.bones == null) {
                        var setupVertices = vertexAttachment.vertices;
                        for (var i = 0; i < vertexCount; i++) {
                            vertices[i] += lastVertices[i] - setupVertices[i];
                        }
                    }
                    else {
                        for (var i = 0; i < vertexCount; i++)
                            vertices[i] += lastVertices[i];
                    }
                }
                else {
                    arrayCopy(lastVertices, 0, vertices, 0, vertexCount);
                }
            }
            else {
                switch (blend) {
                    case MixBlend.setup: {
                        var vertexAttachment_1 = slotAttachment;
                        if (vertexAttachment_1.bones == null) {
                            var setupVertices = vertexAttachment_1.vertices;
                            for (var i = 0; i < vertexCount; i++) {
                                var setup = setupVertices[i];
                                vertices[i] = setup + (lastVertices[i] - setup) * alpha;
                            }
                        }
                        else {
                            for (var i = 0; i < vertexCount; i++)
                                vertices[i] = lastVertices[i] * alpha;
                        }
                        break;
                    }
                    case MixBlend.first:
                    case MixBlend.replace:
                        for (var i = 0; i < vertexCount; i++)
                            vertices[i] += (lastVertices[i] - vertices[i]) * alpha;
                    case MixBlend.add:
                        var vertexAttachment = slotAttachment;
                        if (vertexAttachment.bones == null) {
                            var setupVertices = vertexAttachment.vertices;
                            for (var i = 0; i < vertexCount; i++) {
                                vertices[i] += (lastVertices[i] - setupVertices[i]) * alpha;
                            }
                        }
                        else {
                            for (var i = 0; i < vertexCount; i++)
                                vertices[i] += lastVertices[i] * alpha;
                        }
                }
            }
            return;
        }
        //找的后一帧时间
        var frame = binarySearch$2(frames, time);
        var prevVertices = frameVertices[frame - 1];
        var nextVertices = frameVertices[frame];
        var frameTime = frames[frame];
        var percent = this.curve.getCurvePercent(frame - 1, 1 - (time - frameTime) / (frames[frame - 1] - frameTime));
        if (alpha == 1) {
            if (blend == MixBlend.add) {
                var vertexAttachment = slotAttachment;
                if (vertexAttachment.bones == null) {
                    var setupVertices = vertexAttachment.vertices;
                    for (var i = 0; i < vertexCount; i++) {
                        var prev = prevVertices[i];
                        vertices[i] += prev + (nextVertices[i] - prev) * percent - setupVertices[i];
                    }
                }
                else {
                    for (var i = 0; i < vertexCount; i++) {
                        var prev = prevVertices[i];
                        vertices[i] += prev + (nextVertices[i] - prev) * percent;
                    }
                }
            }
            else {
                for (var i = 0; i < vertexCount; i++) {
                    var prev = prevVertices[i];
                    vertices[i] = prev + (nextVertices[i] - prev) * percent;
                }
            }
        }
        else {
            switch (blend) {
                case MixBlend.setup: {
                    var vertexAttachment_2 = slotAttachment;
                    if (vertexAttachment_2.bones == null) {
                        var setupVertices = vertexAttachment_2.vertices;
                        for (var i = 0; i < vertexCount; i++) {
                            var prev = prevVertices[i], setup = setupVertices[i];
                            vertices[i] = setup + (prev + (nextVertices[i] - prev) * percent - setup) * alpha;
                        }
                    }
                    else {
                        for (var i = 0; i < vertexCount; i++) {
                            var prev = prevVertices[i];
                            vertices[i] = (prev + (nextVertices[i] - prev) * percent) * alpha;
                        }
                    }
                    break;
                }
                case MixBlend.first:
                case MixBlend.replace:
                    for (var i = 0; i < vertexCount; i++) {
                        var prev = prevVertices[i];
                        vertices[i] += (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha;
                    }
                    break;
                case MixBlend.add:
                    var vertexAttachment = slotAttachment;
                    if (vertexAttachment.bones == null) {
                        var setupVertices = vertexAttachment.vertices;
                        for (var i = 0; i < vertexCount; i++) {
                            var prev = prevVertices[i];
                            vertices[i] += (prev + (nextVertices[i] - prev) * percent - setupVertices[i]) * alpha;
                        }
                    }
                    else {
                        for (var i = 0; i < vertexCount; i++) {
                            var prev = prevVertices[i];
                            vertices[i] += (prev + (nextVertices[i] - prev) * percent) * alpha;
                        }
                    }
            }
        }
    };
    return SpineDeformAniTrack;
}(BaseTrack));

var AttachmentAniTrack = /** @class */ (function (_super) {
    __extends(AttachmentAniTrack, _super);
    function AttachmentAniTrack(
    /**
     * 需要改变附件的插槽
     */
    slot, 
    /**
     * 记录所有时间的数组，按顺序递增，没有的按最后一个时间的数据
     */
    times, 
    /**
     * 初始，原始数据中获取的
     */
    // public originAttachment: Attachment
    spine) {
        var _this = _super.call(this) || this;
        _this.slot = slot;
        _this.times = times;
        _this.spine = spine;
        _this._instanceType = "AttachmentAniTrack";
        // 处理下默认数据
        times.forEach(function (t) { t.time = t.time || 0; });
        return _this;
    }
    AttachmentAniTrack.prototype.resetValue = function () {
        this.slot.setToSetupPose();
    };
    AttachmentAniTrack.prototype.setValue = function (time, alpha, blend, direction) {
        if (blend === void 0) { blend = MixBlend.replace; }
        if (direction === void 0) { direction = MixDirection.in; }
        var slot = this.slot;
        if (direction == MixDirection.out && blend == MixBlend.setup) { //还原成默认的。
            var attachmentName_1 = slot.data.attachment;
            slot.setAttachment(attachmentName_1 ? this.spine.getAttachment(this.spine.slots.indexOf(slot), attachmentName_1) : null);
            return;
        }
        var frames = this.times;
        if (time < frames[0].time) {
            if (blend == MixBlend.setup || blend == MixBlend.first || blend == MixBlend.replace) { //replace是后加的,待测试有没有问题
                var attachmentName_1 = slot.data.attachment;
                slot.setAttachment(attachmentName_1 ? this.spine.getAttachment(this.spine.slots.indexOf(slot), attachmentName_1) : null);
            }
            return;
        }
        var frameIndex = 0;
        if (time >= frames[frames.length - 1].time)
            frameIndex = frames.length - 1;
        else
            frameIndex = binarySearch$1(frames, time) - 1;
        var attachmentName = frames[frameIndex].name;
        slot.setAttachment(attachmentName == null ? null : this.spine.getAttachment(this.spine.slots.indexOf(slot), attachmentName));
    };
    return AttachmentAniTrack;
}(BaseTrack));
function binarySearch$1(values, target) {
    var low = 0;
    var high = values.length - 2;
    if (high == 0)
        return 1;
    var current = high >>> 1;
    while (true) {
        if (values[current + 1].time <= target)
            low = current + 1;
        else
            high = current;
        if (low == high)
            return low + 1;
        current = (low + high) >>> 1;
    }
}

var DrawOrderAniTrack = /** @class */ (function (_super) {
    __extends(DrawOrderAniTrack, _super);
    function DrawOrderAniTrack(slots, drawOrder, times) {
        var _this = _super.call(this) || this;
        _this.slots = slots;
        _this.drawOrder = drawOrder;
        _this.times = times;
        _this._instanceType = "DrawOrderAniTrack";
        return _this;
    }
    DrawOrderAniTrack.prototype.setValue = function (time, alpha, blend, direction) {
        if (blend === void 0) { blend = MixBlend.replace; }
        if (direction === void 0) { direction = MixDirection.in; }
        var drawOrder = this.drawOrder;
        var slots = this.slots;
        if (direction == MixDirection.out && blend == MixBlend.setup) {
            arrayCopy(slots, 0, drawOrder, 0, slots.length);
            return;
        }
        var frames = this.times;
        if (time < frames[0].time) {
            if (blend == MixBlend.setup || blend == MixBlend.first)
                arrayCopy(slots, 0, drawOrder, 0, slots.length);
            return;
        }
        var frame = 0;
        if (time >= frames[frames.length - 1].time)
            frame = frames.length - 1;
        else
            frame = binarySearch(frames, time) - 1;
        var drawOrderToSetupIndex = frames[frame].drawOrder;
        if (!drawOrderToSetupIndex)
            arrayCopy(slots, 0, drawOrder, 0, slots.length);
        else {
            for (var i = 0, n = drawOrderToSetupIndex.length; i < n; i++)
                drawOrder[i] = slots[drawOrderToSetupIndex[i]];
        }
    };
    /**
     * 层级需要加个重置方法，因为部分动画并没有层级时间轴，会导致当前动画层级根据上一个动画来
     */
    DrawOrderAniTrack.prototype.resetValue = function () {
        var _this = this;
        this.slots.forEach(function (s, i) {
            _this.drawOrder[i] = s;
        });
    };
    return DrawOrderAniTrack;
}(BaseTrack));
function binarySearch(values, target) {
    var low = 0;
    var high = values.length - 2;
    if (high == 0)
        return 1;
    var current = high >>> 1;
    while (true) {
        if (values[current + 1].time <= target)
            low = current + 1;
        else
            high = current;
        if (low == high)
            return low + 1;
        current = (low + high) >>> 1;
    }
}

var SpineAniClip = /** @class */ (function (_super) {
    __extends(SpineAniClip, _super);
    function SpineAniClip() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        _this.alpha = 1;
        _this.blend = MixBlend.replace;
        _this.direction = MixDirection.in;
        return _this;
    }
    SpineAniClip.prototype.rectify = function () {
        if (!this.tracks || !this.tracks.length)
            return;
        for (var i = 0; i < this.tracks.length; i++) {
            //@ts-ignore
            this.tracks[i].setValue(this.curTime, this.alpha, this.blend, this.direction);
        }
        //设置相等
        this.lastTime = this.curTime;
    };
    return SpineAniClip;
}(AnimationClip));
var SpineAniManager = /** @class */ (function (_super) {
    __extends(SpineAniManager, _super);
    function SpineAniManager() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    /**
     * 切换动画
     * 有切换闪帧问题时尝试setTimeout延时0后执行showAni，
     * 因为resetState更新的部分插槽初始值并不是0时间，所以延时到本帧结束，下帧开始前，利用下帧逻辑覆盖显示
     * @param name
     * @param loops
     * @param callback
     * @param mix 带这个后，上一个动画的回调可能会失效，得看过度时间，对于有某些，a动画隐藏的皮肤，b动画没有处理该插槽，需要重置去掉a动画的效果,最好别赋值mix
     */
    SpineAniManager.prototype.showAni = function (name, loops, callback, mix) {
        if (loops === void 0) { loops = 0; }
        if (mix === void 0) { mix = 0; }
        //如果不设置过度
        if (!mix || !this.currentClip) {
            return _super.prototype.showAni.call(this, name, loops, callback);
        }
        var from = this.currentClip;
        var to = this.getAniClipByName(name);
        if (!to)
            return null;
        //同一个动作
        if (from == to) {
            return _super.prototype.showAni.call(this, name, loops, callback);
        }
        if (from.fromClip) {
            this.resetFrom(from.fromClip);
            from.fromClip = null;
        }
        to.mixTime = 0;
        to.mixDuration = mix;
        to.fromClip = from;
        (this.currentClip = to).startAniRange(0, undefined, loops, callback);
        //返回当前
        return this.currentClip;
    };
    SpineAniManager.prototype.update = function (deltaTime) {
        if (deltaTime === void 0) { deltaTime = 0.0167; }
        this.applyMixingFrom(this.currentClip, deltaTime, MixBlend.first);
        //更新过度的
        _super.prototype.update.call(this, deltaTime);
    };
    SpineAniManager.prototype.applyMixingFrom = function (to, deltaTime, blend) {
        if (!to)
            return;
        var from = to.fromClip;
        if (!from)
            return;
        to.mixTime += deltaTime;
        // if (from.mixingFrom != null)
        //     this.applyMixingFrom(from, skeleton, blend);
        var mix = 0;
        if (to.mixDuration == 0) {
            mix = 1;
            if (blend == MixBlend.first)
                blend = MixBlend.setup;
        }
        else {
            mix = to.mixTime / to.mixDuration;
            if (mix > 1)
                mix = 1;
            if (blend != MixBlend.first)
                blend = from.blend;
        }
        to.alpha = mix;
        //执行赋值
        from.alpha = 1 - mix;
        from.blend = blend;
        if (from.alpha == 0) {
            this.resetFrom(from);
            //@ts-ignore 单独对attachMent的进行一次重置，因为本来就硬切，不会有太大影响
            to.fromClip.tracks.forEach(function (t) {
                if (t.instanceType == "AttachmentAniTrack")
                    t.resetValue();
            });
            to.fromClip = null;
        }
    };
    SpineAniManager.prototype.resetFrom = function (from) {
        //@ts-ignore
        from._isPlaying = false;
        from.alpha = 1;
        from.blend = MixBlend.replace;
    };
    return SpineAniManager;
}(AnimationManager));

/**
 * 记录bone之间的ik关系，需要记录target parent，child
 * 全部计算后再来算一边ik的，
 * 涉及到的parent和child的子级都得更新一边，到时想办法优化，否则子级每帧都会计算两次了
 * 还有order暂时没用起来，后续路径约束啥的加上，需要用了
 */
var IkConstraint = /** @class */ (function (_super) {
    __extends(IkConstraint, _super);
    function IkConstraint(target, bones) {
        var _this = _super.call(this) || this;
        _this.bendDirection = 1;
        _this.compress = false;
        _this.stretch = false;
        _this.uniform = false;
        _this.mix = 1;
        _this.softness = 0;
        _this.active = false;
        _this._instanceType = "IkConstraint";
        _this.target = target;
        _this.bones = bones;
        return _this;
        //构造完后各自赋值吧
        // this.mix = data.mix;
        // this.softness = data.softness;
        // this.bendDirection = data.bendDirection;
        // this.compress = data.compress;
        // this.stretch = data.stretch;
    }
    IkConstraint.prototype.destroy = function () {
    };
    IkConstraint.prototype.isActive = function () {
        return this.active;
    };
    IkConstraint.prototype.apply = function () {
        this.update();
    };
    IkConstraint.prototype.update = function () {
        var target = this.target;
        var bones = this.bones;
        var wx = target.worldMatrix.tx, wy = target.worldMatrix.ty;
        switch (bones.length) {
            case 1:
                this.apply1(bones[0], wx, wy, this.compress, this.stretch, this.uniform, this.mix);
                break;
            case 2:
                this.apply2(bones[0], bones[1], wx, wy, this.bendDirection, this.stretch, this.softness, this.mix);
                break;
        }
    };
    /**
     * Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified in the world
     * coordinate system.
     */
    IkConstraint.prototype.apply1 = function (bone, targetX, targetY, compress, stretch, uniform, alpha) {
        // if (!bone.appliedValid) bone.updateAppliedTransform();
        var p = bone.parent.worldMatrix;
        var pa = p.a, pb = p.c, pc = p.b, pd = p.d;
        var rotationIK = -bone.ashearX - bone.arotation, tx = 0, ty = 0;
        switch (bone.data.transform) {
            case TransformType.onlyTranslation:
                tx = targetX - bone.worldMatrix.tx;
                ty = targetY - bone.worldMatrix.ty;
                break;
            case TransformType.noRotationOrReflection:
                rotationIK += Math.atan2(pc, pa) * RAD_TO_DEG;
                var ps = Math.abs(pa * pd - pb * pc) / (pa * pa + pc * pc);
                pb = -pc * ps;
                pd = pa * ps;
            // Fall through
            default:
                var x = targetX - p.tx, y = targetY - p.ty;
                var d = pa * pd - pb * pc;
                tx = (x * pd - y * pb) / d - bone.ax;
                ty = (y * pa - x * pc) / d - bone.ay;
        }
        rotationIK += Math.atan2(ty, tx) * RAD_TO_DEG;
        if (bone.ascaleX < 0)
            rotationIK += 180;
        if (rotationIK > 180)
            rotationIK -= 360;
        else if (rotationIK < -180)
            rotationIK += 360;
        var sx = bone.ascaleX, sy = bone.ascaleY;
        if (compress || stretch) {
            switch (bone.data.transform) {
                case TransformType.noScale:
                case TransformType.noScaleOrReflection:
                    tx = targetX - bone.worldMatrix.tx;
                    ty = targetY - bone.worldMatrix.ty;
            }
            var b = bone.data.length * sx, dd = Math.sqrt(tx * tx + ty * ty);
            if ((compress && dd < b) || (stretch && dd > b) && b > 0.0001) {
                var s = (dd / b - 1) * alpha + 1;
                sx *= s;
                if (uniform)
                    sy *= s;
            }
        }
        bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, bone.ashearX, bone.ashearY);
    };
    /**
     * Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as possible. The
     * target is specified in the world coordinate system.
     * @param child
     * A direct descendant of the parent bone.
     */
    IkConstraint.prototype.apply2 = function (parent, child, targetX, targetY, bendDir, stretch, softness, alpha) {
        if (alpha == 0) {
            // child.updateTransform();
            return;
        }
        // if (!parent.appliedValid) parent.updateAppliedTransform();
        // if (!child.appliedValid) child.updateAppliedTransform();
        var px = parent.ax, py = parent.ay, psx = parent.ascaleX, sx = psx, psy = parent.ascaleY, csx = child.ascaleX;
        var pmat = parent.matrix;
        var os1 = 0, os2 = 0, s2 = 0;
        if (psx < 0) {
            psx = -psx;
            os1 = 180;
            s2 = -1;
        }
        else {
            os1 = 0;
            s2 = 1;
        }
        if (psy < 0) {
            psy = -psy;
            s2 = -s2;
        }
        if (csx < 0) {
            csx = -csx;
            os2 = 180;
        }
        else
            os2 = 0;
        var cx = child.ax, cy = 0, cwx = 0, cwy = 0, a = pmat.a, b = pmat.c, c = pmat.b, d = pmat.d;
        var u = Math.abs(psx - psy) <= 0.0001;
        if (!u) {
            cy = 0;
            cwx = a * cx + pmat.tx;
            cwy = c * cx + pmat.ty;
        }
        else {
            cy = child.ay;
            cwx = a * cx + b * cy + pmat.tx;
            cwy = c * cx + d * cy + pmat.ty;
        }
        var pp = parent.parent.worldMatrix;
        a = pp.a;
        b = pp.c;
        c = pp.b;
        d = pp.d;
        var id = 1 / (a * d - b * c), x = cwx - pp.tx, y = cwy - pp.ty;
        var dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py;
        var l1 = Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1, a2;
        if (l1 < 0.0001) {
            this.apply1(parent, targetX, targetY, false, stretch, false, alpha);
            child.updateWorldTransformWith(cx, cy, 0, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY);
            return;
        }
        x = targetX - pp.tx;
        y = targetY - pp.ty;
        var tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py;
        var dd = tx * tx + ty * ty;
        if (softness != 0) {
            softness *= psx * (csx + 1) / 2;
            var td = Math.sqrt(dd), sd = td - l1 - l2 * psx + softness;
            if (sd > 0) {
                var p = Math.min(1, sd / (softness * 2)) - 1;
                p = (sd - softness * (1 - p * p)) / td;
                tx -= p * tx;
                ty -= p * ty;
                dd = tx * tx + ty * ty;
            }
        }
        outer: if (u) {
            l2 *= psx;
            var cos = (dd - l1 * l1 - l2 * l2) / (2 * l1 * l2);
            if (cos < -1)
                cos = -1;
            else if (cos > 1) {
                cos = 1;
                if (stretch)
                    sx *= (Math.sqrt(dd) / (l1 + l2) - 1) * alpha + 1;
            }
            a2 = Math.acos(cos) * bendDir;
            a = l1 + l2 * cos;
            b = l2 * Math.sin(a2);
            a1 = Math.atan2(ty * a - tx * b, tx * a + ty * b);
        }
        else {
            a = psx * l2;
            b = psy * l2;
            var aa = a * a, bb = b * b, ta = Math.atan2(ty, tx);
            c = bb * l1 * l1 + aa * dd - aa * bb;
            var c1 = -2 * bb * l1, c2 = bb - aa;
            d = c1 * c1 - 4 * c2 * c;
            if (d >= 0) {
                var q = Math.sqrt(d);
                if (c1 < 0)
                    q = -q;
                q = -(c1 + q) / 2;
                var r0 = q / c2, r1 = c / q;
                var r = Math.abs(r0) < Math.abs(r1) ? r0 : r1;
                if (r * r <= dd) {
                    y = Math.sqrt(dd - r * r) * bendDir;
                    a1 = ta - Math.atan2(y, r);
                    a2 = Math.atan2(y / psy, (r - l1) / psx);
                    break outer;
                }
            }
            var minAngle = Math.PI, minX = l1 - a, minDist = minX * minX, minY = 0;
            var maxAngle = 0, maxX = l1 + a, maxDist = maxX * maxX, maxY = 0;
            c = -a * l1 / (aa - bb);
            if (c >= -1 && c <= 1) {
                c = Math.acos(c);
                x = a * Math.cos(c) + l1;
                y = b * Math.sin(c);
                d = x * x + y * y;
                if (d < minDist) {
                    minAngle = c;
                    minDist = d;
                    minX = x;
                    minY = y;
                }
                if (d > maxDist) {
                    maxAngle = c;
                    maxDist = d;
                    maxX = x;
                    maxY = y;
                }
            }
            if (dd <= (minDist + maxDist) / 2) {
                a1 = ta - Math.atan2(minY * bendDir, minX);
                a2 = minAngle * bendDir;
            }
            else {
                a1 = ta - Math.atan2(maxY * bendDir, maxX);
                a2 = maxAngle * bendDir;
            }
        }
        var os = Math.atan2(cy, cx) * s2;
        var rotation = parent.arotation;
        a1 = (a1 - os) * RAD_TO_DEG + os1 - rotation;
        if (a1 > 180)
            a1 -= 360;
        else if (a1 < -180)
            a1 += 360;
        parent.updateWorldTransformWith(px, py, rotation + a1 * alpha, sx, parent.ascaleY, 0, 0);
        rotation = child.arotation;
        a2 = ((a2 + os) * RAD_TO_DEG - child.ashearX) * s2 + os2 - rotation;
        if (a2 > 180)
            a2 -= 360;
        else if (a2 < -180)
            a2 += 360;
        child.updateWorldTransformWith(cx, cy, rotation + a2 * alpha, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY);
    };
    return IkConstraint;
}(HashObject));

var ClippingAttachment = /** @class */ (function (_super) {
    __extends(ClippingAttachment, _super);
    function ClippingAttachment() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        _this.color = new SpineColor(0.2275, 0.2275, 0.8078, 1);
        return _this;
    }
    return ClippingAttachment;
}(VertexAttachment));

var SkinType;
(function (SkinType) {
    //区域，纯图片，没有类型字段就是默认region
    SkinType["region"] = "region";
    SkinType["mesh"] = "mesh";
    //遮罩
    SkinType["clipping"] = "clipping";
    SkinType["linkedmesh"] = "linkedmesh";
    SkinType["path"] = "path";
    SkinType["point"] = "point";
})(SkinType || (SkinType = {}));
var tempRgb = [0, 0, 0];
/**
 * TODO 性能略差，到时考虑单独写着色器，和3d那样断批处理，单独开着色器，传骨骼矩阵等等，绘制Mesh
 * 参考spine runtime和three
 * 事件暂时不需要，基本都走播放回调，或者到时把eventTrack和监听加进来，
 */
var Spine = /** @class */ (function (_super) {
    __extends(Spine, _super);
    function Spine(spineData, showBones) {
        if (showBones === void 0) { showBones = false; }
        var _this = _super.call(this) || this;
        _this.spineData = spineData;
        /**
         * 帧率，即每秒帧数，默认60
         */
        _this.fps = 60;
        _this._instanceType = "Spine";
        //数据赋值
        var data = spineData;
        //如果没有纹理，把骨骼加上
        if (!spineData.textures)
            showBones = true;
        //自行反向？
        _this.scaleY = -1;
        //骨骼处理
        if (data.bones) {
            _this.boneContainer = _this.addChild(new Container());
            _this.bones = [];
            //先看看骨骼
            for (var i = 0; i < data.bones.length; i++) {
                //需要显示骨骼才传入，
                var bone = new Bone(data.bones[i], showBones ? _this.boneContainer : null);
                _this.bones.push(bone);
                if (!bone.data.parent) {
                    _this.boneContainer.addChild(bone);
                }
                else {
                    var pb = _this.findBone(bone.data.parent);
                    if (pb)
                        pb.addChild(bone);
                }
                // let boneData = data.bones[i];
                // let bone: Bone;
                // if (!boneData.parent)
                //     bone = new Bone(boneData);
                // else {
                //     var pb = this.findBone(boneData.parent)
                //     bone = new Bone(boneData, pb);
                //     pb.children.push(bone);
                // }
                // this.bones.push(bone);
            }
            //排序
            // this.orderCalculations = [];
            // for (var i = 0; i < this.bones.length; i++)this.sortBone(this.bones[i]);
        }
        //ik约束,还有各种约束，到时order有用
        if (data.ik) {
            _this.ikConstraints = [];
            data.ik.forEach(function (ik) {
                var ikConstraint = new IkConstraint(_this.findBone(ik.target), ik.bones.map(function (b) { return _this.findBone(b); }));
                ikConstraint.mix = ik.mix === undefined ? 1 : ik.mix;
                ikConstraint.softness = ik.softness === undefined ? 0 : ik.softness;
                ikConstraint.bendDirection = (ik.bendDirection === undefined ? true : ik.bendDirection) ? 1 : -1;
                ikConstraint.compress = ik.compress === undefined ? false : ik.compress;
                ikConstraint.stretch = ik.stretch === undefined ? false : ik.stretch;
                ikConstraint.uniform = ik.uniform === undefined ? false : ik.uniform;
                _this.ikConstraints.push(ikConstraint);
            });
        }
        //插槽
        if (data.slots) {
            _this.slotContainer = _this.addChildAt(new Container(), 0);
            _this.slots = [];
            _this.tempClipContainers = [];
            for (var i_1 = 0; i_1 < data.slots.length; i_1++) {
                var slotMap_1 = data.slots[i_1];
                var bone = _this.findBone(slotMap_1.bone);
                _this.slots.push(_this.slotContainer.addChild(new Slot(bone, slotMap_1, _this)));
                _this.tempClipContainers.push(null); //新加
                // if(slotMap.attachment){//下面处理
                //     
                // }
            }
            //复制一份
            _this.drawOrder = _this.slots.slice();
        }
        //皮肤数据
        if (data.skins) {
            _this.skins = [];
            var orginSkins_1 = data.skins;
            //是数组，那就转一下
            if (Object.prototype.toString.call(data.skins) === '[object Array]') {
                orginSkins_1 = {};
                //@ts-ignore
                data.skins.forEach(function (e) {
                    orginSkins_1[e.name] = e.attachments;
                });
            }
            for (var skinName in orginSkins_1) {
                var skinMap = orginSkins_1[skinName];
                var skin = new Skin(skinName);
                for (var slotName in skinMap) {
                    var slotIndex = _this.findSlotIndex(slotName);
                    if (slotIndex == -1)
                        throw new Error("Slot not found: " + slotName);
                    var slotMap = skinMap[slotName];
                    for (var entryName in slotMap) {
                        var attachment = _this.readAttachment(slotMap[entryName], skin, slotIndex, entryName, null);
                        if (attachment != null)
                            skin.addAttachment(slotIndex, entryName, attachment);
                    }
                }
                _this.skins.push(skin);
                if (skin.name == "default")
                    _this.defaultSkin = skin;
            }
            //默认皮肤
            // this.skin = this.defaultSkin;
        }
        //动画数据
        if (data.animations) {
            var animationClips = [];
            //一级是总动画
            for (var aniName in data.animations) {
                //这里开始收集track;
                var tracks = [];
                var duration = 0;
                var mm = data.animations[aniName];
                //骨骼，基本没啥问题了
                if (mm.bones) {
                    for (var aboneName in mm.bones) {
                        var boneAniData = mm.bones[aboneName];
                        var bone = _this.findBone(aboneName);
                        for (var boneAniName in boneAniData) {
                            //@ts-ignore
                            var boneTrack = new SpineBoneAniTrack(bone, boneAniName, boneAniData[boneAniName]);
                            tracks.push(boneTrack);
                            duration = Math.max(duration, boneTrack.times[boneTrack.times.length - 1].time);
                        }
                    }
                }
                //插槽的切换
                if (mm.slots) {
                    for (var slotName_1 in mm.slots) {
                        var slotMap_2 = mm.slots[slotName_1];
                        var slotIndex_1 = _this.findSlotIndex(slotName_1);
                        var slot = _this.slots[slotIndex_1];
                        for (var timelineName_1 in slotMap_2) {
                            var timelineMap_1 = slotMap_2[timelineName_1];
                            var endTime = timelineMap_1[timelineMap_1.length - 1].time;
                            if (timelineName_1 == "attachment") {
                                tracks.push(
                                // 处理下
                                new AttachmentAniTrack(slot, timelineMap_1, _this));
                                duration = Math.max(duration, endTime || 0);
                            }
                            else if (timelineName_1 == "color") {
                                tracks.push(new SpineColorAniTrack(slot, timelineMap_1));
                                duration = Math.max(duration, endTime || 0);
                            }
                            // else if (timelineName == "twoColor") {
                            //     var timeline = new core.TwoColorTimeline(timelineMap.length);
                            //     timeline.slotIndex = slotIndex;
                            //     var frameIndex = 0;
                            //     for (var i = 0; i < timelineMap.length; i++) {
                            //         var valueMap = timelineMap[i];
                            //         var light = new core.Color();
                            //         var dark = new core.Color();
                            //         light.setFromString(valueMap.light);
                            //         dark.setFromString(valueMap.dark);
                            //         timeline.setFrame(frameIndex, valueMap.time, light.r, light.g, light.b, light.a, dark.r, dark.g, dark.b);
                            //         this.readCurve(valueMap, timeline, frameIndex);
                            //         frameIndex++;
                            //     }
                            //     timelines.push(timeline);
                            //     duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * core.TwoColorTimeline.ENTRIES]);
                            // }
                            // else
                            //     throw new Error("Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")");
                        }
                    }
                }
                //变形
                if (mm.deform) {
                    for (var deformName in mm.deform) {
                        var deformMap = mm.deform[deformName];
                        //主套皮肤
                        var skin_1 = _this.findSkin(deformName);
                        for (var slotName in deformMap) {
                            var slotMap_3 = deformMap[slotName];
                            var slotIndex_2 = _this.findSlotIndex(slotName);
                            var slot = _this.slots[slotIndex_2]; //this.findSlot(slotName);
                            for (var timelineName in slotMap_3) {
                                var timelineMap = slotMap_3[timelineName];
                                var attachment_1 = skin_1.getAttachment(slotIndex_2, timelineName);
                                var deformTrack = new SpineDeformAniTrack(slot, attachment_1, timelineMap);
                                tracks.push(deformTrack);
                                duration = Math.max(duration, deformTrack.frameTimes[deformTrack.frameTimes.length - 1]);
                            }
                        }
                    }
                }
                //顺序mm
                var drawOrderNode = mm.drawOrder; //|| mm["draworder"];
                if (drawOrderNode) { //只会有一个
                    var dat = new DrawOrderAniTrack(_this.slots, _this.drawOrder, drawOrderNode.map(function (d) {
                        return {
                            time: d.time || 0,
                            drawOrder: (function () {
                                var offsets = d.offsets;
                                if (!offsets)
                                    return null;
                                var slotCount = _this.slots.length;
                                var drawOrder = newArray(slotCount, -1);
                                var unchanged = newArray(slotCount - offsets.length, 0);
                                var originalIndex = 0, unchangedIndex = 0;
                                for (var i = 0; i < offsets.length; i++) {
                                    var offsetMap = offsets[i];
                                    var slotIndex = _this.findSlotIndex(offsetMap.slot);
                                    while (originalIndex != slotIndex)
                                        unchanged[unchangedIndex++] = originalIndex++;
                                    drawOrder[originalIndex + offsetMap.offset] = originalIndex++;
                                }
                                while (originalIndex < slotCount)
                                    unchanged[unchangedIndex++] = originalIndex++;
                                for (var i = slotCount - 1; i >= 0; i--)
                                    if (drawOrder[i] == -1)
                                        drawOrder[i] = unchanged[--unchangedIndex];
                                return drawOrder;
                            })()
                        };
                    }));
                    tracks.push(dat);
                    duration = Math.max(duration, dat.times[dat.times.length - 1].time);
                }
                //事件的先不管
                // if(mm.events){}
                var clip = new SpineAniClip(tracks, duration);
                clip.name = aniName;
                animationClips.push(clip);
            }
            //动画都放进manager，到时和AnimationClip都要改，传入mix和blend，现在先不管
            _this.animationManager = new SpineAniManager(animationClips);
        }
        //默认皮肤搞一次
        if (data.slots) {
            //默认的皮肤先干
            for (var i_2 = 0; i_2 < _this.slots.length; i_2++) {
                var slot = _this.slots[i_2];
                if (slot.data.attachment) {
                    var attachment_2 = _this.defaultSkin.getAttachment(i_2, slot.data.attachment);
                    // slot.originAttachment = attachment;//原始的赋值一个
                    slot.setAttachment(attachment_2);
                    if (attachment_2 instanceof RegionAttachment) {
                        var spriteName = attachment_2.name;
                        var sprite = _this.createSprite(slot, attachment_2, spriteName);
                        slot.currentSprite = sprite;
                        slot.currentSpriteName = spriteName;
                        slot.addChild(sprite);
                    }
                    else if (attachment_2 instanceof MeshAttachment) {
                        var mesh = _this.createMesh(slot, attachment_2);
                        slot.currentMesh = mesh;
                        slot.currentMeshName = attachment_2.name;
                        slot.addChild(mesh);
                    }
                    else if (attachment_2 instanceof ClippingAttachment) {
                        _this.createGraphics(slot, attachment_2);
                        slot.addChild(slot.clippingContainer);
                        slot.addChild(slot.currentGraphics);
                    }
                }
            }
        }
        return _this;
    }
    Spine.prototype.findBone = function (name) {
        var bones = this.bones;
        for (var i = 0, n = bones.length; i < n; i++) {
            var bone = bones[i];
            if (bone.name == name)
                return bone;
        }
        return null;
    };
    Spine.prototype.sortBone = function (bone) {
        if (bone.sorted)
            return;
        var parent = bone.parent;
        if (parent)
            this.sortBone(parent);
        bone.sorted = true;
        this.orderCalculations.push(bone);
    };
    /**
     * 根据插槽名字或者插槽
     * @param slotName
     */
    Spine.prototype.findSlot = function (slotName) {
        var arr = this.slots;
        for (var i = 0; i < arr.length; i++) {
            if (arr[i].name == slotName)
                return arr[i];
        }
        return null;
    };
    Spine.prototype.findSlotIndex = function (slotName) {
        var arr = this.slots;
        for (var i = 0; i < arr.length; i++) {
            if (arr[i].name == slotName)
                return i;
        }
        return -1;
    };
    Spine.prototype.findSkin = function (skinName) {
        var skins = this.skins;
        for (var i = 0, n = skins.length; i < n; i++) {
            var skin = skins[i];
            if (skin.name == skinName)
                return skin;
        }
        return null;
    };
    Spine.prototype.getAttachment = function (slotIndex, attachmentName) {
        if (this.skin) {
            var at = this.skin.getAttachment(slotIndex, attachmentName);
            if (at)
                return at;
        }
        if (this.defaultSkin) {
            var at = this.defaultSkin.getAttachment(slotIndex, attachmentName);
            if (at)
                return at;
        }
        return null;
        // return (this.skin || this.defaultSkin).getAttachment(slotIndex, attachmentName) || null
    };
    Spine.prototype.update = function () {
        var now = Date.now();
        var delta = this.lastTime ? (now - this.lastTime) * 0.001 : 0.01667;
        this.lastTime = now;
        //动画更新，比如bone的基础属性
        this.animationManager.update(delta * this.fps / 60);
        // this.updateSlots();
        // this.updateDrawOrder();放到下面执行
        _super.prototype.update.call(this);
    };
    //重写。只有骨骼的进入计算，插槽的根着骨骼世界矩阵计算
    Spine.prototype.updateTransform = function () {
        //自己先算
        this.transform.updateWorldMatrix(this.parent.transform);
        this._worldAlpha = this.alpha * this.parent._worldAlpha;
        //保证先计算骨骼的
        this.boneContainer && this.boneContainer.updateTransform();
        //计算ik约束的
        this.ikConstraints && this.ikConstraints.forEach(function (ik) { ik.update(); });
        // for (var i = 0; i < this.orderCalculations.length; i++)this.orderCalculations[i].update();
        this.updateSlots();
        this.updateDrawOrder();
        this.slotContainer.updateTransform();
    };
    //显示对象呈现
    Spine.prototype.updateSlots = function () {
        for (var i = 0, n = this.slots.length; i < n; i++) {
            var slot = this.slots[i];
            var attachment = slot.attachment;
            if (!attachment) {
                slot.visible = false;
                continue;
            }
            var attColor = attachment.color;
            if (attachment instanceof RegionAttachment) {
                if (slot.currentMesh) {
                    slot.currentMesh.visible = false;
                    slot.currentMesh = null;
                    slot.currentMeshName = undefined;
                }
                if (!slot.currentSpriteName || slot.currentSpriteName !== attachment.name) {
                    var spriteName = attachment.name;
                    if (slot.currentSprite) {
                        slot.currentSprite.visible = false;
                    }
                    slot.sprites = slot.sprites || {};
                    if (slot.sprites[spriteName] !== undefined) {
                        slot.sprites[spriteName].visible = true;
                    }
                    else {
                        var sprite = this.createSprite(slot, attachment, spriteName);
                        slot.addChild(sprite);
                    }
                    slot.currentSprite = slot.sprites[spriteName];
                    slot.currentSpriteName = spriteName;
                }
                var transform = slot.transform;
                // slot.bone.worldMatrix.decompose(transform);
                slot.bone.matrix.decompose(transform);
                transform._localID++;
                tempRgb[0] = slot.color.r * attColor.r;
                tempRgb[1] = slot.color.g * attColor.g;
                tempRgb[2] = slot.color.b * attColor.b;
                slot.currentSprite.tint = rgb2hex$1(tempRgb);
                // slot.currentSprite.blendMode = slot.blendMode;
            }
            else if (attachment instanceof MeshAttachment) {
                if (slot.currentSprite) {
                    slot.currentSprite.visible = false;
                    slot.currentSprite = null;
                    slot.currentSpriteName = undefined;
                    //切换一个初始的transform
                    var transform = new Transform();
                    transform._parentID = -1;
                    transform._worldID = slot.transform._worldID;
                    slot.transform = transform;
                }
                if (!slot.currentMeshName || slot.currentMeshName !== attachment.name) {
                    var meshName = attachment.name;
                    if (slot.currentMesh) {
                        slot.currentMesh.visible = false;
                    }
                    slot.meshes = slot.meshes || {};
                    if (slot.meshes[meshName] !== undefined) {
                        slot.meshes[meshName].visible = true;
                    }
                    else {
                        var mesh = this.createMesh(slot, attachment);
                        slot.addChild(mesh);
                    }
                    slot.currentMesh = slot.meshes[meshName];
                    slot.currentMeshName = meshName;
                }
                attachment.computeWorldVerticesOld(slot, slot.currentMesh._vertices, this.bones);
                //@ts-ignore
                slot.currentMesh._vertexDirty++;
                //颜色处理
                tempRgb[0] = slot.color.r * attColor.r;
                tempRgb[1] = slot.color.g * attColor.g;
                tempRgb[2] = slot.color.b * attColor.b;
                slot.currentMesh.tint = rgb2hex$1(tempRgb);
                // slot.currentMesh.blendMode = slot.blendMode;
            }
            else if (attachment instanceof ClippingAttachment) {
                if (!slot.currentGraphics) {
                    this.createGraphics(slot, attachment);
                    slot.addChild(slot.clippingContainer);
                    slot.addChild(slot.currentGraphics);
                }
                this.updateGraphics(slot, attachment);
            }
            else {
                slot.visible = false;
                continue;
            }
            slot.visible = true;
            slot.alpha = slot.color.a;
        }
    };
    /**
     * 遮罩的先不管，有了再说
     */
    Spine.prototype.updateDrawOrder = function () {
        var drawOrder = this.drawOrder;
        var clippingAttachment = null;
        var clippingContainer = null;
        for (var i = 0, n = drawOrder.length; i < n; i++) {
            var index = this.slots.indexOf(drawOrder[i]);
            var slot = this.slots[index];
            // if (!clippingContainer) {
            //     if (slot.parent && slot.parent !== this.slotContainer) {
            //         // slot.parent.removeChild(slot);
            //         // slot.parent = this;
            //     }
            // }
            if (slot.currentGraphics && slot.attachment) {
                clippingContainer = slot.clippingContainer;
                clippingAttachment = slot.attachment;
                // clippingContainer.children.length = 0;
                clippingContainer.removeAllChildren();
                // this.slotContainer.children[i] = slot;
                this.slotContainer.addChildAt(slot, i);
                if (clippingAttachment.endSlot == slot.data) {
                    clippingAttachment.endSlot = null;
                }
            }
            else {
                if (clippingContainer) {
                    var c = this.tempClipContainers[i];
                    if (!c) {
                        c = this.tempClipContainers[i] = new Container();
                        c.visible = false;
                    }
                    // this.slotContainer.children[i] = c;
                    this.slotContainer.addChildAt(c, i);
                    // slot.parent = null;
                    clippingContainer.addChild(slot);
                    if (clippingAttachment.endSlot == slot.data) {
                        // clippingContainer.renderable = true;
                        clippingContainer = null;
                        clippingAttachment = null;
                    }
                }
                else {
                    // this.children[i] = slotContainer;
                    this.slotContainer.addChildAt(slot, i); //.children[i] = slot;
                }
            }
        }
    };
    Spine.prototype.readAttachment = function (map, skin, slotIndex, name, skeletonData) {
        var textures = this.spineData.textures;
        //@ts-ignore
        name = map.name || name;
        var type = map.type || SkinType.region;
        switch (type) {
            case SkinType.region: {
                var region = new RegionAttachment(name, map.x, map.y, map.scaleX, map.scaleY, map.rotation, map.width, map.height, textures && textures[map.path || name]);
                if (map.color)
                    region.color.setFromString(map.color);
                return region;
            }
            case SkinType.mesh: {
                var mesh = new MeshAttachment(name);
                mesh.texture = textures && textures[map.path || name];
                // var color = this.getValue(map, "color", null);
                // if (color != null)
                //     mesh.color.setFromString(color);
                var uvs = map.uvs;
                this.readVertices(map, mesh, uvs.length);
                mesh.triangles = map.triangles;
                mesh.regionUVs = new Float32Array(uvs);
                mesh.hullLength = map.hull * 2 || 0;
                return mesh;
            }
            case SkinType.clipping: {
                var clip = new ClippingAttachment(name);
                if (clip == null)
                    return null;
                var end = map.end; //不用null判断，end不会是0或false
                if (end) {
                    var slot = this.findSlot(end);
                    if (slot == null)
                        throw new Error("Clipping end slot not found: " + end);
                    clip.endSlot = slot.data;
                }
                var vertexCount = map.vertexCount;
                this.readVertices(map, clip, vertexCount << 1);
                var color = map.color;
                if (color)
                    clip.color.setFromString(color);
                return clip;
            }
        }
        return null;
    };
    Spine.prototype.readVertices = function (map, attachment, verticesLength) {
        attachment.worldVerticesLength = verticesLength;
        var vertices = map.vertices;
        if (verticesLength == vertices.length) {
            var scaledVertices = new Float32Array(vertices);
            attachment.vertices = scaledVertices;
            return;
        }
        var weights = new Array();
        var bones = new Array();
        for (var i = 0, n = vertices.length; i < n;) {
            var boneCount = vertices[i++];
            bones.push(boneCount);
            for (var nn = i + boneCount * 4; i < nn; i += 4) {
                bones.push(vertices[i]);
                weights.push(vertices[i + 1]);
                weights.push(vertices[i + 2]);
                weights.push(vertices[i + 3]);
            }
        }
        attachment.bones = bones;
        attachment.vertices = new Float32Array(weights);
    };
    Spine.prototype.createSprite = function (slot, attachment, defName) {
        var sprite = new Sprite(attachment.texture);
        sprite.rotation = attachment.rotation || 0;
        sprite.anchorTexture.set(0.5, 0.5);
        // sprite.scaleY = -1;//放在这里很悬，目前没法线sprite有缩放的情况
        // sprite.anchor.x = 0.5;
        // sprite.anchor.y = 0.5;
        sprite.position.x = attachment.x;
        sprite.position.y = attachment.y;
        sprite.alpha = attachment.color.a;
        //判断纹理是否存在
        if (attachment.texture) {
            sprite.scaleX = attachment.scaleX * attachment.width / attachment.texture.width;
            //注意加个负号
            sprite.scaleY = -attachment.scaleY * attachment.height / attachment.texture.height;
        }
        slot.sprites = slot.sprites || {};
        slot.sprites[defName] = sprite;
        return sprite;
    };
    Spine.prototype.createMesh = function (slot, attachment) {
        var strip = new Mesh(attachment.texture, new Float32Array(attachment.regionUVs.length), attachment.regionUVs, new Uint16Array(attachment.triangles));
        /*if (strip.canvasPadding)*/ strip.canvasPadding = 1.5;
        strip.refresh(true);
        strip.multiplyUvs();
        // strip.alpha = attachment.color.a;
        slot.meshes = slot.meshes || {};
        slot.meshes[attachment.name] = strip;
        return strip;
    };
    Spine.prototype.createGraphics = function (slot, clip) {
        var graphics = new Graphics();
        graphics.beginFill(0xffffff, 1);
        graphics.drawPolygon([]);
        slot.currentGraphics = graphics;
        slot.clippingContainer = new Container();
        slot.clippingContainer.mask = slot.currentGraphics;
        return graphics;
    };
    Spine.prototype.updateGraphics = function (slot, clip) {
        var geom = slot.currentGraphics;
        var vertices = geom.graphicsData[0].shape.points;
        var n = clip.worldVerticesLength;
        vertices.length = n;
        clip.computeWorldVertices(slot, 0, n, vertices, 0, 2, this.bones);
        // geom.invalidate();//暂时感觉没用
    };
    /**
     * 返回一个Spine，注意data原始数据不能修改，之前写了那些多，忘了里面有没有修改
     */
    Spine.prototype.clone = function () {
        return new Spine(this.spineData);
    };
    // setSkin(name: string) {
    //     var skin = this.findSkin(name);
    //     if (skin) {
    //         if (this.skin)
    //             skin.attachAll(this.slots, this.skin);
    //         else {
    //             var slots = this.slots;
    //             for (var i = 0, n = slots.length; i < n; i++) {
    //                 var slot = slots[i];
    //                 var name_1 = slot.data.attachment;
    //                 if (name_1) {
    //                     var attachment = skin.getAttachment(i, name_1);
    //                     if (attachment)
    //                         slot.setAttachment(attachment);
    //                 }
    //             }
    //         }
    //         this.skin = skin;
    //     }
    // }
    Spine.prototype.setSkin = function (name) {
        var skin = this.findSkin(name);
        //皮肤不存在
        if (!skin)
            return;
        //皮肤一致
        if (this.skin == skin)
            return;
        //
        if (this.addSkin(skin))
            return;
        //如果要替换成默认的皮肤，
        if (skin == this.defaultSkin) {
            this.resetSkin();
        }
        else {
            //先重置皮肤，再用下面的换装，因为可能出现非一致插槽换装
            this.resetSkin();
            this.addSkin(skin);
        }
    };
    Spine.prototype.resetSkin = function () {
        this.skin = this.defaultSkin;
        this.slots.forEach(function (s) { s.setToSetupPose(); });
    };
    /**
     * 原先是默认皮肤，然后添加新皮肤
     */
    Spine.prototype.addSkin = function (skin) {
        if (this.skin && this.skin != this.defaultSkin)
            return false;
        var slots = this.slots;
        for (var i = 0, n = slots.length; i < n; i++) {
            var slot = slots[i];
            var name_1 = slot.data.attachment;
            if (name_1) {
                var attachment = skin.getAttachment(i, name_1);
                if (attachment)
                    slot.setAttachment(attachment);
            }
        }
        this.skin = skin;
        return true;
    };
    Object.defineProperty(Spine.prototype, "skinNames", {
        /**
         * 获取所有皮肤名字
         */
        get: function () {
            if (!this.skins || !this.skins.length)
                return [];
            return this.skins.map(function (s) { return s.name; });
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Spine.prototype, "aniNames", {
        /**
         * 获取所有动画的名字
         */
        get: function () {
            var am = this.animationManager;
            //@ts-ignore
            if (!am || !am.animationClips || !am.animationClips.length)
                return [];
            //@ts-ignore
            return am.animationClips.map(function (s) { return s.name; });
        },
        enumerable: false,
        configurable: true
    });
    return Spine;
}(Container));
// function calculateTotalTime(tracks: SpineBoneAniTrack[]) {
//     var duration = 0;
//     for (var i = 0, n = tracks.length; i !== n; ++i) {
//         var track = tracks[i];
//         duration = Math.max(duration, track.times[track.times.length - 1].time);
//     }
//     return duration
// }

/**
 * 为了不影响原2djson图集的rotate判断，这里单独搞，rotate是6
 * @param url
 * @param onLoad 参数就是图集的对象
 * @param onError
 * @param imgUrl 不传会用url替换成png为图片路径
 */
function loadAtlas(url, onLoad, onError, imgUrl) {
    //替换后缀改成.png
    imgUrl = imgUrl || url.replace(".atlas", ".png");
    Promise.all([
        //数据
        new Promise(function (r) {
            GlobalLoader.loadText(function (s, res) {
                r(s ? res : null);
            }, url);
        }),
        //图片
        new Promise(function (r) {
            GlobalLoader.loadImage(function (s, image) {
                r(s ? BaseTexture.fromImage(image) : null);
            }, imgUrl);
        })
    ]).then(function (results) {
        if (results[0] && results[1]) {
            var textures = createTexturesByAtlas(results[1], results[0]);
            onLoad && onLoad(textures);
        }
        else {
            onError && onError("load failed for atlas:" + url);
        }
    });
}
//由于旋转角度问题，单开方法
function createTexturesByAtlas(baseTexture, altaData) {
    var textures = {};
    //解析数据
    var reader = new AtlasReader(altaData);
    var tuple = new Array(4);
    var json = null;
    while (true) {
        var line = reader.readLine();
        // console.log(line)
        if (line == null)
            break;
        line = line.trim();
        if (line.length == 0) ;
        else if (!json) { //把下面的干回去，头部信息，暂时不用，但要读完
            json = {};
            if (reader.readTuple(tuple) == 2) {
                // page.width = parseInt(tuple[0]);
                // page.height = parseInt(tuple[1]);
                reader.readTuple(tuple);
            }
            reader.readTuple(tuple);
            // page.minFilter = core.Texture.filterFromString(tuple[0]);
            // page.magFilter = core.Texture.filterFromString(tuple[1]);
            reader.readValue();
            // page.uWrap = core.TextureWrap.ClampToEdge;
            // page.vWrap = core.TextureWrap.ClampToEdge;
            // if (direction == "x")
            //     page.uWrap = core.TextureWrap.Repeat;
            // else if (direction == "y")
            //     page.vWrap = core.TextureWrap.Repeat;
            // else if (direction == "xy")
            //     page.uWrap = page.vWrap = core.TextureWrap.Repeat;
        }
        else { //下面的就是所有数据了
            var rotation = reader.readValue() == "true" ? 6 : 0;
            reader.readTuple(tuple);
            var x = parseInt(tuple[0]);
            var y = parseInt(tuple[1]);
            reader.readTuple(tuple);
            var w = parseInt(tuple[0]);
            var h = parseInt(tuple[1]);
            if (reader.readTuple(tuple) == 4) {
                if (reader.readTuple(tuple) == 4) {
                    reader.readTuple(tuple);
                }
            }
            var sw = parseInt(tuple[0]);
            var sh = parseInt(tuple[1]);
            reader.readTuple(tuple);
            var ox = parseInt(tuple[0]); /// resolution;
            var oy = parseInt(tuple[1]); /// resolution;
            var frame = null;
            //裁切的数据
            var trim = null;
            //贴图原始尺寸
            var orig = new Rectangle(0, 0, Math.floor(sw), Math.floor(sh));
            //如果旋转过
            if (rotation) {
                frame = new Rectangle(Math.floor(x), Math.floor(y), Math.floor(h), Math.floor(w));
            }
            else {
                frame = new Rectangle(Math.floor(x), Math.floor(y), Math.floor(w), Math.floor(h));
            }
            //如果是被截掉过透明边界的 ,,加上如果和原始尺寸不一致也是裁切
            if (ox || oy || w != sw || h != sh) {
                //其实就是在orig上切图，偏移
                // trim = new Rectangle(
                //     Math.floor(ox),
                //     Math.floor(oy),
                //     Math.floor(w),
                //     Math.floor(h)
                // );
                //斟酌是否有必要用Math.floor，包括上面所有的
                trim = new Rectangle(ox, sh - h - oy, w, h);
            }
            //暂时不考虑进全局图集
            textures[line] = new Texture(baseTexture, frame, orig, trim, rotation);
            //index:-1读完
            /*region.index = parseInt(*/ reader.readValue() /*)*/;
        }
    }
    return textures;
}
var AtlasReader = /** @class */ (function () {
    function AtlasReader(text) {
        this.index = 0;
        this.lines = text.split(/\r\n|\r|\n/);
    }
    AtlasReader.prototype.readLine = function () {
        if (this.index >= this.lines.length)
            return null;
        return this.lines[this.index++];
    };
    AtlasReader.prototype.readValue = function () {
        var line = this.readLine();
        var colon = line.indexOf(":");
        if (colon == -1)
            throw new Error("Invalid line: " + line);
        return line.substring(colon + 1).trim();
    };
    AtlasReader.prototype.readTuple = function (tuple) {
        var line = this.readLine();
        var colon = line.indexOf(":");
        if (colon == -1)
            throw new Error("Invalid line: " + line);
        var i = 0, lastMatch = colon + 1;
        for (; i < 3; i++) {
            var comma = line.indexOf(",", lastMatch);
            if (comma == -1)
                break;
            tuple[i] = line.substr(lastMatch, comma - lastMatch).trim();
            lastMatch = comma + 1;
        }
        tuple[i] = line.substring(lastMatch).trim();
        return i + 1;
    };
    return AtlasReader;
}());

/**
 * 加载spi文件，直接返回显示对象吧，数据不暴露了，spine有clone方法，用原数据生成，以后有需求单独加载数据再说
 * @param url
 * @param onLoad 到底怎么返回，只返回数据吧，对象自己new，还是直接返回对象，其实数据没必要暴露，svga是因为解析不带任何显示对象，只能返回数据
 * @param onError
 */
function loadSpine(url, onLoad, onError) {
    var _this = this;
    GlobalLoader.loadAB(function (s, res) { return __awaiter(_this, void 0, void 0, function () {
        return __generator(this, function (_a) {
            if (!s) {
                onError && onError(res);
                return [2 /*return*/];
            }
            try {
                parseSpineData(res, onLoad);
            }
            catch (e) {
                onError && onError(e);
            }
            return [2 /*return*/];
        });
    }); }, url);
}
/**
 * 解析spi后缀文件加载的数据
 * @param binary spi后缀的二进制数据
 * @param onComplete
 */
function parseSpineData(binary, onComplete) {
    var headerView = new DataView(binary, 0, 12);
    var imgLen = headerView.getUint32(0, true), atlasLen = headerView.getUint32(4, true), jsonLen = headerView.getUint32(8, true);
    var base64String = "data:image/png;base64," + ArrayBufferToBase64(binary.slice(12, imgLen + 12));
    var atlas = decodeText(new Uint8Array(binary, 12 + imgLen, atlasLen));
    var json = JSON.parse(decodeText(new Uint8Array(binary, 12 + imgLen + atlasLen, jsonLen)));
    GlobalLoader.loadImage(function (s, image) {
        //纹理加上
        json.textures = createTexturesByAtlas(BaseTexture.fromImage(image), atlas);
        // //后续删除
        // Object.defineProperty(json, 'spine', {
        //     get: function () {
        //         console.warn("loadSpine方法不再返回spine对象，请使用new Spine(spineData)生成实例");
        //         return new Spine(json)
        //     }
        // })
        // //后续删除
        // Object.defineProperty(json, 'skeletonData', {
        //     get: function () {
        //         console.warn("loadSpine方法返回的是整个skeletonData了，不再是json.skeletonData");
        //         console.warn("Spine构造函数直接传loadSpine加载成功的数据就行，不再分开传skeletonData和textures");
        //         return json
        //     }
        // })
        //成功回调
        onComplete && onComplete(json);
    }, base64String);
}

var FpsPanel = /** @class */ (function (_super) {
    __extends(FpsPanel, _super);
    /**
     * 帧率面板
     * 后续可以加入每次drawCall，总绘制对象等等
     */
    function FpsPanel() {
        var _this = _super.call(this) || this;
        _this.bgColor = '#002002';
        _this.textColor = '#0ff0ff';
        _this.PR = 3;
        _this.WIDTH = 80 * _this.PR;
        _this.HEIGHT = 48 * _this.PR;
        _this.TEXT_X = 3 * _this.PR;
        _this.TEXT_Y = 2 * _this.PR;
        _this.GRAPH_X = 3 * _this.PR;
        _this.GRAPH_Y = 15 * _this.PR;
        _this.GRAPH_WIDTH = 74 * _this.PR;
        _this.GRAPH_HEIGHT = 30 * _this.PR;
        _this.GRAPH_SIZE = 74;
        _this.maxValue = 120;
        _this.min = Infinity;
        _this.max = 0;
        _this.items = [];
        _this.lastTime = Date.now();
        _this.frames = 0;
        //离屏canvas
        var canvas = createCanvas();
        canvas.width = _this.WIDTH;
        canvas.height = _this.HEIGHT;
        _this.texture = Texture.fromCanvas(canvas);
        _this.context = canvas.getContext("2d");
        _this.context.font = 'bold ' + (9 * _this.PR) + 'px Helvetica,Arial,sans-serif';
        _this.context.textBaseline = 'top';
        _this.updateText("FPS");
        return _this;
    }
    FpsPanel.prototype.reset = function () {
        this.lastTime = Date.now();
        this.min = Infinity;
        this.max = 0;
        this.items.length = 0;
        this.frames = 0;
    };
    FpsPanel.prototype.update = function () {
        this.frames++;
        var time = Date.now();
        //每秒跑一次
        if (time >= this.lastTime + 1000) {
            var value = (this.frames * 1000) / (time - this.lastTime);
            this.updatePanel(value);
            this.lastTime = time;
            this.frames = 0;
        }
        _super.prototype.update.call(this);
    };
    FpsPanel.prototype.updatePanel = function (value) {
        var _a = this, items = _a.items, GRAPH_SIZE = _a.GRAPH_SIZE, context = _a.context, GRAPH_X = _a.GRAPH_X, textColor = _a.textColor, GRAPH_Y = _a.GRAPH_Y, PR = _a.PR, GRAPH_HEIGHT = _a.GRAPH_HEIGHT, bgColor = _a.bgColor, maxValue = _a.maxValue;
        items.push(value);
        while (items.length > GRAPH_SIZE) {
            items.shift();
        }
        this.min = Math.min(this.min, value);
        this.max = Math.max(this.max, value);
        this.updateText(Math.round(value) + ' FPS (' + Math.round(this.min) + '-' + Math.round(this.max) + ')');
        for (var i = 0; i < items.length; i++) {
            var startPos = GRAPH_X + (i + GRAPH_SIZE - items.length) * PR;
            context.fillStyle = textColor;
            context.globalAlpha = 1;
            context.fillRect(startPos, GRAPH_Y, PR, GRAPH_HEIGHT);
            context.fillStyle = bgColor;
            context.globalAlpha = 0.9;
            context.fillRect(startPos, GRAPH_Y, PR, Math.round((1 - (items[i] / maxValue)) * GRAPH_HEIGHT));
        }
        this.texture.update();
    };
    FpsPanel.prototype.updateText = function (text) {
        var _a = this, context = _a.context, bgColor = _a.bgColor, textColor = _a.textColor, WIDTH = _a.WIDTH, HEIGHT = _a.HEIGHT, TEXT_X = _a.TEXT_X, TEXT_Y = _a.TEXT_Y, GRAPH_X = _a.GRAPH_X, GRAPH_Y = _a.GRAPH_Y, GRAPH_WIDTH = _a.GRAPH_WIDTH, GRAPH_HEIGHT = _a.GRAPH_HEIGHT;
        context.fillStyle = bgColor;
        context.globalAlpha = 1;
        context.fillRect(0, 0, WIDTH, HEIGHT);
        context.fillStyle = textColor;
        context.fillText(text, TEXT_X, TEXT_Y);
        context.fillRect(GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT);
        context.fillStyle = bgColor;
        context.globalAlpha = 0.9;
        context.fillRect(GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT);
    };
    return FpsPanel;
}(Sprite));

export { AdjustmentFilter, AdvancedBloomFilter, AlphaFilter, AmbientLight, AnimationTrack3D, AnimationType3D, ArrayBufferToBase64, AxesHelper, BLEND_MODES, BaseMaterial, BaseTexture, BaseTextureCache, BitmapText, BlurFilter, BlurFilterNew, BlurXFilter, BlurYFilter, Box3Helper, BoxGeometry, Button, CanvasRenderer, CircleGeometry, ColorMatrixFilter, Container, CylinderGeometry, D3Renderer, DEG_TO_RAD, DRAW_MODES, DirectionalLight, DisplacementFilter, DisplayObject, Ease, EditableText, EnvBlendType, EnvType, Euler, Event, EventDispatcher, FXAAFilter, Filter, FloatDisplay, FpsPanel, FrameAni, GC_MODES, GLBuffer, GLFramebuffer, GLShader, GLTexture, Geometry, GlobalLoader, Graphics, GridHelper, GroupD8, INT_BITS1, INT_MAX, INT_MIN, InputText, LINE_ALIGNMENT, LINE_CAP, LINE_JOIN, LightMaterial, Loader, Lottie, Matrix, Matrix4, Mesh, Mesh3D, MouseEvent, MovieClip, NineSlicePlane, NoiseFilter, Object3D, ObservablePoint, OrthographicCamera, PI_2, PRECISION, PerspectiveCamera, Plane, PlaneGeometry, Point, PointLight, Quaternion, RAD_TO_DEG, RENDERER_TYPE, Raycaster, Rectangle, RenderSideType, RenderTexture, ResponseDataType, RingGeometry, Rope, RotationOrders, SCALE_MODES, SHAPES, Scene3D, ScrollList, ScrollListItem, ScrollPage, ScrollView, ShaderMaterial, ShadowType, Shape, SphereGeometry, Spine, Sprite, Sprite3D, Sprite3dMaterial, SpriteMaskFilter, Stage, SvgaAni, TEXT_ALIGN, TEXT_GRADIENT, TEXT_lINETYPE, TextField, Texture, TextureCache, TorusGeometry, Transform, Tween, UniformType, VERSION, VERTICAL_ALIGN, Vector2, Vector3, VertexArrayObject, WRAP_MODES, WebglRenderer, abs, calculatePlaneIndices, cancelAnimationFrame, checkMaxIfStatementsInShader, clamp, clearTextureCache, cos, countTrailingZeros, createCanvas, createContext, createImage, createTextureSheet, createTexturesByAtlas, decodeText, defaultFragmentShader3d, defaultValue, defaultVertexShader3d, deinterleave2, deinterleave3, destroyCanvasContent, destroyTbCanvas, destroyTextureCache, getBackupCanvasCtx, getCanvasBitmapStyle, getDevicePixelRatio, getEnv, getGradientColor, getOsType, getRGBA, hex2rgb$1 as hex2rgb, hex2string, initedByCanvas, initedByTbCanvas, interleave2, interleave3, isPow2, isWebGLSupported, loadArrayBuffer, loadAtlas, loadGltf, loadImage, loadJson, loadRaw, loadSheet, loadSpine, loadText, log10, log2, max, min, nextCombination, nextPow2, parity, parseGltf, parseSpineData, popCount, premultiplyTint, prevPow2, removeItems, requestAnimationFrame, reverse, rgb2hex$1 as rgb2hex, setEnv, sign, sin, string2hex, toDisplayDataURL, uid };
//# sourceMappingURL=fyge.esm.js.map
