element
@@ -52,6 +53,13 @@ var AudioClip = cc.Class({
},
properties: {
+ /**
+ * !#en Get the audio clip duration
+ * !#zh 获取音频剪辑的长度
+ * @property duration
+ * @type {Number}
+ */
+ duration: 0,
loadMode: {
default: LoadMode.WEB_AUDIO,
type: LoadMode
@@ -61,37 +69,62 @@ var AudioClip = cc.Class({
return this._audio;
},
set (value) {
- this._audio = value;
- if (value) {
+ // HACK: fix load mp3 as audioClip, _nativeAsset is set as audioClip.
+ // Should load mp3 as audioBuffer indeed.
+ if (value instanceof cc.AudioClip) {
+ this._audio = value._nativeAsset;
+ }
+ else {
+ this._audio = value;
+ }
+ if (this._audio) {
this.loaded = true;
this.emit('load');
}
},
override: true
+ },
+
+ _nativeDep: {
+ get () {
+ return { uuid: this._uuid, audioLoadMode: this.loadMode, ext: cc.path.extname(this._native), __isNative__: true };
+ },
+ override: true
}
},
statics: {
LoadMode: LoadMode,
_loadByUrl: function (url, callback) {
- var item = cc.loader.getItem(url) || cc.loader.getItem(url + '?useDom=1');
- if (!item || !item.complete) {
- cc.loader.load(url, function (error, downloadUrl) {
+ var audioClip = cc.assetManager.assets.get(url);
+ if (!audioClip) {
+ cc.assetManager.loadRemote(url, function (error, data) {
if (error) {
return callback(error);
}
- item = cc.loader.getItem(url) || cc.loader.getItem(url + '?useDom=1');
- callback(null, item.content);
+ callback(null, data);
});
}
else {
- if (item._owner instanceof AudioClip) {
- // preloaded and retained by audio clip
- callback(null, item._owner);
- }
- else {
- callback(null, item.content);
- }
+ callback(null, audioClip);
+ }
+ }
+ },
+
+ _ensureLoaded (onComplete) {
+ if (this.loaded) {
+ return onComplete && onComplete();
+ }
+ else {
+ if (onComplete) {
+ this.once('load', onComplete);
+ }
+ if (!this._loading) {
+ this._loading = true;
+ let self = this;
+ cc.assetManager.postLoadNative(this, function (err) {
+ self._loading = false;
+ });
}
}
},
diff --git a/cocos2d/core/assets/CCBitmapFont.js b/cocos2d/core/assets/CCBitmapFont.js
index 45340968c60..fdffe30fd8d 100644
--- a/cocos2d/core/assets/CCBitmapFont.js
+++ b/cocos2d/core/assets/CCBitmapFont.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -24,6 +24,59 @@
THE SOFTWARE.
****************************************************************************/
+let FontLetterDefinition = function() {
+ this.u = 0;
+ this.v = 0;
+ this.w = 0;
+ this.h = 0;
+ this.offsetX = 0;
+ this.offsetY = 0;
+ this.textureID = 0;
+ this.valid = false;
+ this.xAdvance = 0;
+};
+
+let FontAtlas = function (texture) {
+ this._letterDefinitions = {};
+ this._texture = texture;
+};
+
+FontAtlas.prototype = {
+ constructor: FontAtlas,
+ addLetterDefinitions (letter, letterDefinition) {
+ this._letterDefinitions[letter] = letterDefinition;
+ },
+ cloneLetterDefinition () {
+ let copyLetterDefinitions = {};
+ for (let key in this._letterDefinitions) {
+ let value = new FontLetterDefinition();
+ cc.js.mixin(value, this._letterDefinitions[key]);
+ copyLetterDefinitions[key] = value;
+ }
+ return copyLetterDefinitions;
+ },
+ getTexture () {
+ return this._texture;
+ },
+ getLetter (key) {
+ return this._letterDefinitions[key];
+ },
+ getLetterDefinitionForChar (char) {
+ let key = char.charCodeAt(0);
+ let hasKey = this._letterDefinitions.hasOwnProperty(key);
+ let letter;
+ if (hasKey) {
+ letter = this._letterDefinitions[key];
+ } else {
+ letter = null;
+ }
+ return letter;
+ },
+ clear () {
+ this._letterDefinitions = {};
+ }
+};
+
/**
* @module cc
*/
@@ -52,9 +105,42 @@ var BitmapFont = cc.Class({
default: -1
},
//用来缓存 BitmapFont 解析之后的数据
- _fntConfig: null
+ _fntConfig: null,
+ _fontDefDictionary: null
+ },
+
+ onLoad () {
+ let spriteFrame = this.spriteFrame;
+ if (!this._fontDefDictionary && spriteFrame) {
+ this._fontDefDictionary = new FontAtlas(spriteFrame._texture);
+ }
+
+ let fntConfig = this._fntConfig;
+ if (!fntConfig) {
+ return;
+ }
+ let fontDict = fntConfig.fontDefDictionary;
+ for (let fontDef in fontDict) {
+ let letter = new FontLetterDefinition();
+
+ let rect = fontDict[fontDef].rect;
+ letter.offsetX = fontDict[fontDef].xOffset;
+ letter.offsetY = fontDict[fontDef].yOffset;
+ letter.w = rect.width;
+ letter.h = rect.height;
+ letter.u = rect.x;
+ letter.v = rect.y;
+ //FIXME: only one texture supported for now
+ letter.textureID = 0;
+ letter.valid = true;
+ letter.xAdvance = fontDict[fontDef].xAdvance;
+
+ this._fontDefDictionary.addLetterDefinitions(fontDef, letter);
+ }
}
});
cc.BitmapFont = BitmapFont;
+cc.BitmapFont.FontLetterDefinition = FontLetterDefinition;
+cc.BitmapFont.FontAtlas = FontAtlas;
module.exports = BitmapFont;
diff --git a/cocos2d/core/load-pipeline/binary-downloader.js b/cocos2d/core/assets/CCBufferAsset.js
similarity index 63%
rename from cocos2d/core/load-pipeline/binary-downloader.js
rename to cocos2d/core/assets/CCBufferAsset.js
index de4097f4ea9..24fb0f7a398 100644
--- a/cocos2d/core/load-pipeline/binary-downloader.js
+++ b/cocos2d/core/assets/CCBufferAsset.js
@@ -24,29 +24,32 @@
THE SOFTWARE.
****************************************************************************/
-function downloadBinary (item, callback) {
- var url = item.url;
- var xhr = cc.loader.getXMLHttpRequest(),
- errInfo = 'Load binary data failed: ' + url + '';
- xhr.open('GET', url, true);
- xhr.responseType = "arraybuffer";
- xhr.onload = function () {
- var arrayBuffer = xhr.response;
- if (arrayBuffer) {
- var result = new Uint8Array(arrayBuffer);
- callback(null, result);
- }
- else {
- callback({status:xhr.status, errorMessage:errInfo + '(no response)'});
+/**
+ * @class BufferAsset
+ * @extends Asset
+ */
+var BufferAsset = cc.Class({
+ name: 'cc.BufferAsset',
+ extends: cc.Asset,
+
+ ctor () {
+ this._buffer = null;
+ },
+
+ properties: {
+ _nativeAsset: {
+ get () {
+ return this._buffer;
+ },
+ set (bin) {
+ this._buffer = bin.buffer || bin;
+ },
+ override: true
+ },
+ buffer () {
+ return this._buffer;
}
- };
- xhr.onerror = function(){
- callback({status:xhr.status, errorMessage:errInfo + '(error)'});
- };
- xhr.ontimeout = function(){
- callback({status:xhr.status, errorMessage:errInfo + '(time out)'});
- };
- xhr.send(null);
-}
-
-module.exports = downloadBinary;
\ No newline at end of file
+ }
+});
+
+cc.BufferAsset = module.exports = BufferAsset;
diff --git a/cocos2d/core/assets/CCFont.js b/cocos2d/core/assets/CCFont.js
index dc1c1eb75f6..21e147c4632 100644
--- a/cocos2d/core/assets/CCFont.js
+++ b/cocos2d/core/assets/CCFont.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/assets/CCJsonAsset.js b/cocos2d/core/assets/CCJsonAsset.js
index 2a6eee38833..b9f4823b168 100644
--- a/cocos2d/core/assets/CCJsonAsset.js
+++ b/cocos2d/core/assets/CCJsonAsset.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/assets/CCLabelAtlas.js b/cocos2d/core/assets/CCLabelAtlas.js
index dd4e63005ba..6412fdbf095 100644
--- a/cocos2d/core/assets/CCLabelAtlas.js
+++ b/cocos2d/core/assets/CCLabelAtlas.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -36,7 +36,20 @@
*/
var LabelAtlas = cc.Class({
name: 'cc.LabelAtlas',
- extends: cc.BitmapFont
+ extends: cc.BitmapFont,
+
+ onLoad () {
+ if (!this.spriteFrame) {
+ cc.warnID(9100, this.name);
+ return;
+ }
+ if (!this._fntConfig) {
+ cc.warnID(9101, this.name);
+ return;
+ }
+ this._super();
+ }
+
});
cc.LabelAtlas = LabelAtlas;
diff --git a/cocos2d/core/assets/CCPrefab.js b/cocos2d/core/assets/CCPrefab.js
index 21517e0f7aa..44c5fcc6650 100644
--- a/cocos2d/core/assets/CCPrefab.js
+++ b/cocos2d/core/assets/CCPrefab.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -117,6 +117,15 @@ var Prefab = cc.Class({
* @default false
*/
asyncLoadAssets: false,
+
+ /**
+ * @property {Boolean} readonly
+ * @default false
+ */
+ readonly: {
+ default: false,
+ editorOnly: true
+ }
},
statics: {
@@ -145,11 +154,7 @@ var Prefab = cc.Class({
// @param {Node} [rootToRedirect] - specify an instantiated prefabRoot that all references to prefabRoot in prefab
// will redirect to
_doInstantiate: function (rootToRedirect) {
- if (this.data._prefab) {
- // prefab asset is always synced
- this.data._prefab._synced = true;
- }
- else {
+ if (!this.data._prefab) {
// temp guard code
cc.warnID(3700);
}
@@ -180,8 +185,6 @@ var Prefab = cc.Class({
this.data._instantiate(node);
}
else {
- // prefab asset is always synced
- this.data._prefab._synced = true;
// instantiate node
node = this.data._instantiate();
}
@@ -194,7 +197,12 @@ var Prefab = cc.Class({
PrefabUtils.linkPrefab(this, node);
}
return node;
- }
+ },
+
+ destroy () {
+ this.data && this.data.destroy();
+ this._super();
+ },
});
cc.Prefab = module.exports = Prefab;
diff --git a/cocos2d/core/assets/CCRawAsset.js b/cocos2d/core/assets/CCRawAsset.js
deleted file mode 100644
index 8d1542551bd..00000000000
--- a/cocos2d/core/assets/CCRawAsset.js
+++ /dev/null
@@ -1,75 +0,0 @@
-/****************************************************************************
- Copyright (c) 2013-2016 Chukong Technologies Inc.
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-var CCObject = require('../platform/CCObject');
-var js = require('../platform/js');
-
-/**
- * !#en
- * The base class for registering asset types.
- * !#zh
- * 注册用的资源基类。
- *
- * @class RawAsset
- * @extends Object
- */
-cc.RawAsset = cc.Class({
- name: 'cc.RawAsset', extends: CCObject,
-
- ctor: function () {
- /**
- * @property _uuid
- * @type {String}
- * @private
- */
- Object.defineProperty(this, '_uuid', {
- value: '',
- writable: true,
- // enumerable is false by default, to avoid uuid being assigned to empty string during destroy
- });
- },
-});
-
-/**
- * @method isRawAssetType
- * @param {Function} ctor
- * @returns {Boolean}
- * @static
- * @private
- */
-js.value(cc.RawAsset, 'isRawAssetType', function (ctor) {
- return js.isChildClassOf(ctor, cc.RawAsset) && !js.isChildClassOf(ctor, cc.Asset);
-});
-
- // TODO - DELME after 2.1
-js.value(cc.RawAsset, 'wasRawAssetType', function (ctor) {
- return ctor === cc.Texture2D ||
- ctor === cc.AudioClip ||
- ctor === cc.ParticleAsset ||
- ctor === cc.Asset; // since 1.10, all raw asset will import as cc.Asset
-});
-
-module.exports = cc.RawAsset;
diff --git a/cocos2d/core/assets/CCRenderTexture.js b/cocos2d/core/assets/CCRenderTexture.js
index 1a3d1008715..85987c6c52b 100644
--- a/cocos2d/core/assets/CCRenderTexture.js
+++ b/cocos2d/core/assets/CCRenderTexture.js
@@ -1,8 +1,40 @@
const renderer = require('../renderer');
-const renderEngine = require('../renderer/render-engine');
-const gfx = renderEngine.gfx;
const Texture2D = require('./CCTexture2D');
+import gfx from '../../renderer/gfx';
+
+/**
+ * !#en The depth buffer and stencil buffer format for RenderTexture.
+ * !#zh RenderTexture 的深度缓冲以及模板缓冲格式。
+ * @enum RenderTexture.DepthStencilFormat
+ */
+let DepthStencilFormat = cc.Enum({
+ /**
+ * !#en 24 bit depth buffer and 8 bit stencil buffer
+ * !#zh 24 位深度缓冲和 8 位模板缓冲
+ * @property RB_FMT_D24S8
+ * @readonly
+ * @type {number}
+ */
+ RB_FMT_D24S8: gfx.RB_FMT_D24S8,
+ /**
+ * !#en Only 8 bit stencil buffer
+ * !#zh 只申请 8 位模板缓冲
+ * @property RB_FMT_S8
+ * @readonly
+ * @type {number}
+ */
+ RB_FMT_S8: gfx.RB_FMT_S8,
+ /**
+ * !#en Only 16 bit depth buffer
+ * !#zh 只申请 16 位深度缓冲
+ * @property RB_FMT_D16
+ * @readonly
+ * @type {number}
+ */
+ RB_FMT_D16: gfx.RB_FMT_D16
+})
+
/**
* Render textures are textures that can be rendered to.
* @class RenderTexture
@@ -12,6 +44,10 @@ let RenderTexture = cc.Class({
name: 'cc.RenderTexture',
extends: Texture2D,
+ statics: {
+ DepthStencilFormat
+ },
+
ctor () {
this._framebuffer = null;
},
@@ -29,47 +65,47 @@ let RenderTexture = cc.Class({
initWithSize (width, height, depthStencilFormat) {
this.width = Math.floor(width || cc.visibleRect.width);
this.height = Math.floor(height || cc.visibleRect.height);
-
- let opts = {};
- opts.format = this._format;
- opts.width = width;
- opts.height = height;
- opts.images = undefined;
- opts.wrapS = this._wrapS;
- opts.wrapT = this._wrapT;
-
- if (!this._texture) {
- this._texture = new renderer.Texture2D(renderer.device, opts);
- }
- else {
- this._texture.update(opts);
- }
-
- opts = {
+ this._resetUnderlyingMipmaps();
+
+ let opts = {
colors: [ this._texture ],
};
+
+ if (this._depthStencilBuffer) this._depthStencilBuffer.destroy();
+ let depthStencilBuffer;
if (depthStencilFormat) {
- let depthStencilBuffer = new gfx.RenderBuffer(renderer.device, depthStencilFormat, width, height);
+ depthStencilBuffer = new gfx.RenderBuffer(renderer.device, depthStencilFormat, width, height);
if (depthStencilFormat === gfx.RB_FMT_D24S8) {
- opts.depth = opts.stencil = depthStencilBuffer;
+ opts.depthStencil = depthStencilBuffer;
}
else if (depthStencilFormat === gfx.RB_FMT_S8) {
opts.stencil = depthStencilBuffer;
}
- else if (depthStencilFormat === gl.RB_FMT_D16) {
+ else if (depthStencilFormat === gfx.RB_FMT_D16) {
opts.depth = depthStencilBuffer;
}
}
+ this._depthStencilBuffer = depthStencilBuffer;
+ if (this._framebuffer) this._framebuffer.destroy();
+ this._framebuffer = new gfx.FrameBuffer(renderer.device, width, height, opts);
- if (this._framebuffer) {
- this._framebuffer.destroy();
- }
- this._framebuffer = new renderEngine.gfx.FrameBuffer(renderer.device, width, height, opts);
-
+ this._packable = false;
+
this.loaded = true;
this.emit("load");
},
+ updateSize(width, height) {
+ this.width = Math.floor(width || cc.visibleRect.width);
+ this.height = Math.floor(height || cc.visibleRect.height);
+ this._resetUnderlyingMipmaps();
+
+ let rbo = this._depthStencilBuffer;
+ if (rbo) rbo.update(this.width, this.height);
+ this._framebuffer._width = width;
+ this._framebuffer._height = height;
+ },
+
/**
* !#en Draw a texture to the specified position
* !#zh 将指定的图片渲染到指定的位置上
@@ -78,7 +114,7 @@ let RenderTexture = cc.Class({
* @param {Number} y
*/
drawTextureAt (texture, x, y) {
- if (!texture._image) return;
+ if (!texture._image || texture._image.width === 0) return;
this._texture.updateSubImage({
x, y,
@@ -86,7 +122,8 @@ let RenderTexture = cc.Class({
width: texture.width,
height: texture.height,
level: 0,
- flipY: false
+ flipY: false,
+ premultiplyAlpha: texture._premultiplyAlpha
})
},
@@ -117,10 +154,9 @@ let RenderTexture = cc.Class({
let height = h || this.height
data = data || new Uint8Array(width * height * 4);
- let gl = renderer._forward._device._gl;
+ let gl = cc.game._renderContext;
let oldFBO = gl.getParameter(gl.FRAMEBUFFER_BINDING);
- gl.bindFramebuffer(gl.FRAMEBUFFER, this._framebuffer._glID);
- gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this._texture._glID, 0);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, this._framebuffer.getHandle());
gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, data);
gl.bindFramebuffer(gl.FRAMEBUFFER, oldFBO);
@@ -131,6 +167,7 @@ let RenderTexture = cc.Class({
this._super();
if (this._framebuffer) {
this._framebuffer.destroy();
+ this._framebuffer = null;
}
}
});
diff --git a/cocos2d/core/assets/CCSceneAsset.js b/cocos2d/core/assets/CCSceneAsset.js
index f22c6f9fe7a..e5831d940f0 100644
--- a/cocos2d/core/assets/CCSceneAsset.js
+++ b/cocos2d/core/assets/CCSceneAsset.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/assets/CCScripts.js b/cocos2d/core/assets/CCScripts.js
index 22f8a10e829..d3fb10009fb 100644
--- a/cocos2d/core/assets/CCScripts.js
+++ b/cocos2d/core/assets/CCScripts.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -54,20 +54,6 @@ var JavaScript = cc.Class({
cc._JavaScript = JavaScript;
-/**
- * !#en Class for coffeescript handling.
- * !#zh CoffeeScript 资源类。
- * @class CoffeeScript
- * @extends Asset
- *
- */
-var CoffeeScript = cc.Class({
- name: 'cc.CoffeeScript',
- extends: Script,
-});
-
-cc._CoffeeScript = CoffeeScript;
-
/**
* !#en Class for TypeScript handling.
* !#zh TypeScript 资源类。
diff --git a/cocos2d/core/assets/CCSpriteAtlas.js b/cocos2d/core/assets/CCSpriteAtlas.js
index 0dde4587b7a..975887dcfbf 100644
--- a/cocos2d/core/assets/CCSpriteAtlas.js
+++ b/cocos2d/core/assets/CCSpriteAtlas.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/assets/CCSpriteFrame.js b/cocos2d/core/assets/CCSpriteFrame.js
index 908b0a6c13c..cfb95aeac7c 100644
--- a/cocos2d/core/assets/CCSpriteFrame.js
+++ b/cocos2d/core/assets/CCSpriteFrame.js
@@ -26,7 +26,6 @@
****************************************************************************/
const EventTarget = require("../event/event-target");
-const textureUtil = require('../utils/texture-util');
const INSET_LEFT = 0;
const INSET_TOP = 1;
@@ -53,7 +52,7 @@ let temp_uvs = [{u: 0, v: 0}, {u: 0, v: 0}, {u: 0, v: 0}, {u: 0, v: 0}];
* // load a cc.SpriteFrame with image path (Recommend)
* var self = this;
* var url = "test assets/PurpleMonster";
- * cc.loader.loadRes(url, cc.SpriteFrame, function (err, spriteFrame) {
+ * cc.resources.load(url, cc.SpriteFrame, null, function (err, spriteFrame) {
* var node = new cc.Node("New Sprite");
* var sprite = node.addComponent(cc.Sprite);
* sprite.spriteFrame = spriteFrame;
@@ -70,7 +69,7 @@ let SpriteFrame = cc.Class(/** @lends cc.SpriteFrame# */{
_textureSetter: {
set: function (texture) {
if (texture) {
- if (CC_EDITOR && !(texture instanceof cc.Texture2D)) {
+ if (CC_EDITOR && Editor.isBuilder) {
// just building
this._texture = texture;
return;
@@ -78,21 +77,10 @@ let SpriteFrame = cc.Class(/** @lends cc.SpriteFrame# */{
if (this._texture !== texture) {
this._refreshTexture(texture);
}
- this._textureFilename = texture.url;
}
}
},
- // _textureFilename: {
- // get () {
- // return (this._texture && this._texture.url) || "";
- // },
- // set (url) {
- // let texture = cc.textureCache.addImage(url);
- // this._refreshTexture(texture);
- // }
- // },
-
/**
* !#en Top border of the sprite
* !#zh sprite 的顶部边框
@@ -194,6 +182,12 @@ let SpriteFrame = cc.Class(/** @lends cc.SpriteFrame# */{
// the location of the sprite on rendering texture
this._rect = null;
+ // uv data of frame
+ this.uv = [];
+ // texture of frame
+ this._texture = null;
+ // store original info before packed to dynamic atlas
+ this._original = null;
// for trimming
this._offset = null;
@@ -203,19 +197,15 @@ let SpriteFrame = cc.Class(/** @lends cc.SpriteFrame# */{
this._rotated = false;
+ this._flipX = false;
+ this._flipY = false;
+
this.vertices = null;
this._capInsets = [0, 0, 0, 0];
- this.uv = [];
this.uvSliced = [];
- this._texture = null;
- this._textureFilename = '';
-
- // store original info before packed to dynamic atlas
- this._original = null;
-
if (CC_EDITOR) {
// Atlas asset uuid
this._atlasUuid = '';
@@ -238,6 +228,19 @@ let SpriteFrame = cc.Class(/** @lends cc.SpriteFrame# */{
return this._texture && this._texture.loaded;
},
+ onTextureLoaded (callback, target) {
+ if (this.textureLoaded()) {
+ callback.call(target);
+ }
+ else {
+ this.once('load', callback, target);
+ this.ensureLoadTexture();
+ return false;
+ }
+
+ return true;
+ },
+
/**
* !#en Returns whether the sprite frame is rotated in the texture.
* !#zh 获取 SpriteFrame 是否旋转
@@ -256,6 +259,54 @@ let SpriteFrame = cc.Class(/** @lends cc.SpriteFrame# */{
*/
setRotated: function (bRotated) {
this._rotated = bRotated;
+ if (this._texture)
+ this._calculateUV();
+ },
+
+ /**
+ * !#en Returns whether the sprite frame is flip x axis in the texture.
+ * !#zh 获取 SpriteFrame 是否反转 x 轴
+ * @method isFlipX
+ * @return {Boolean}
+ */
+ isFlipX: function () {
+ return this._flipX;
+ },
+
+ /**
+ * !#en Returns whether the sprite frame is flip y axis in the texture.
+ * !#zh 获取 SpriteFrame 是否反转 y 轴
+ * @method isFlipY
+ * @return {Boolean}
+ */
+ isFlipY: function () {
+ return this._flipY;
+ },
+
+ /**
+ * !#en Set whether the sprite frame is flip x axis in the texture.
+ * !#zh 设置 SpriteFrame 是否翻转 x 轴
+ * @method setFlipX
+ * @param {Boolean} flipX
+ */
+ setFlipX: function (flipX) {
+ this._flipX = flipX;
+ if (this._texture) {
+ this._calculateUV();
+ }
+ },
+
+ /**
+ * !#en Set whether the sprite frame is flip y axis in the texture.
+ * !#zh 设置 SpriteFrame 是否翻转 y 轴
+ * @method setFlipY
+ * @param {Boolean} flipY
+ */
+ setFlipY: function (flipY) {
+ this._flipY = flipY;
+ if (this._texture) {
+ this._calculateUV();
+ }
},
/**
@@ -276,8 +327,10 @@ let SpriteFrame = cc.Class(/** @lends cc.SpriteFrame# */{
*/
setRect: function (rect) {
this._rect = rect;
+ if (this._texture)
+ this._calculateUV();
},
-
+
/**
* !#en Returns the original size of the trimmed image.
* !#zh 获取修剪前的原始大小
@@ -322,20 +375,11 @@ let SpriteFrame = cc.Class(/** @lends cc.SpriteFrame# */{
}
let w = texture.width, h = texture.height;
- if (self._rotated && cc.game.renderType === cc.game.RENDER_TYPE_CANVAS) {
- // TODO: rotate texture for canvas
- // self._texture = _ccsg.Sprite.CanvasRenderCmd._createRotatedTexture(texture, self.getRect());
- self._rotated = false;
- w = self._texture.width;
- h = self._texture.height;
- self.setRect(cc.rect(0, 0, w, h));
- }
-
if (self._rect) {
self._checkRect(self._texture);
}
else {
- self.setRect(cc.rect(0, 0, w, h));
+ self._rect = cc.rect(0, 0, w, h);
}
if (!self._originalSize) {
@@ -394,24 +438,26 @@ let SpriteFrame = cc.Class(/** @lends cc.SpriteFrame# */{
* @method clone
* @return {SpriteFrame}
*/
- clone: function () {
- return new SpriteFrame(this._texture || this._textureFilename, this._rect, this._rotated, this._offset, this._originalSize);
+ clone: function() {
+ return new SpriteFrame(this._texture, this.getRect(), this._rotated, this.getOffset(), this.getOriginalSize());
},
/**
* !#en Set SpriteFrame with Texture, rect, rotated, offset and originalSize.
* !#zh 通过 Texture,rect,rotated,offset 和 originalSize 设置 SpriteFrame。
* @method setTexture
- * @param {String|Texture2D} textureOrTextureFile
+ * @param {Texture2D} texture
* @param {Rect} [rect=null]
* @param {Boolean} [rotated=false]
* @param {Vec2} [offset=cc.v2(0,0)]
* @param {Size} [originalSize=rect.size]
* @return {Boolean}
*/
- setTexture: function (textureOrTextureFile, rect, rotated, offset, originalSize) {
+ setTexture: function (texture, rect, rotated, offset, originalSize) {
+ if (arguments.length === 1 && texture === this._texture) return;
+
if (rect) {
- this.setRect(rect);
+ this._rect = rect;
}
else {
this._rect = null;
@@ -433,26 +479,17 @@ let SpriteFrame = cc.Class(/** @lends cc.SpriteFrame# */{
this._rotated = rotated || false;
- // loading texture
- let texture = textureOrTextureFile;
- if (typeof texture === 'string' && texture) {
- this._textureFilename = texture;
- this._loadTexture();
+ if (typeof texture === 'string') {
+ cc.errorID(3401);
+ return;
}
- if (texture instanceof cc.Texture2D && this._texture !== texture) {
+ if (texture instanceof cc.Texture2D) {
this._refreshTexture(texture);
}
return true;
},
- _loadTexture: function () {
- if (this._textureFilename) {
- let texture = textureUtil.loadImage(this._textureFilename);
- this._refreshTexture(texture);
- }
- },
-
/**
* !#en If a loading scene (or prefab) is marked as `asyncLoadAssets`, all the textures of the SpriteFrame which
* associated by user's custom Components in the scene, will not preload automatically.
@@ -476,13 +513,9 @@ let SpriteFrame = cc.Class(/** @lends cc.SpriteFrame# */{
if (!this._texture.loaded) {
// load exists texture
this._refreshTexture(this._texture);
- textureUtil.postLoadTexture(this._texture);
+ cc.assetManager.postLoadNative(this._texture);
}
}
- else if (this._textureFilename) {
- // load new texture
- this._loadTexture();
- }
},
/**
@@ -490,17 +523,9 @@ let SpriteFrame = cc.Class(/** @lends cc.SpriteFrame# */{
* If you do not need to use the SpriteFrame temporarily, you can call this method so that its texture could be garbage collected. Then when you need to render the SpriteFrame, you should call `ensureLoadTexture` manually to reload texture.
* !#zh
* 当你暂时不再使用这个 SpriteFrame 时,可以调用这个方法来保证引用的贴图对象能被 GC。然后当你要渲染 SpriteFrame 时,你需要手动调用 `ensureLoadTexture` 来重新加载贴图。
- *
* @method clearTexture
- * @example
- * spriteFrame.clearTexture();
- * // when you need the SpriteFrame again...
- * spriteFrame.once('load', onSpriteFrameLoaded);
- * spriteFrame.ensureLoadTexture();
+ * @deprecated since 2.1
*/
- clearTexture: function () {
- this._texture = null; // TODO - release texture
- },
_checkRect: function (texture) {
let rect = this._rect;
@@ -514,10 +539,32 @@ let SpriteFrame = cc.Class(/** @lends cc.SpriteFrame# */{
maxY += rect.height;
}
if (maxX > texture.width) {
- cc.errorID(3300, texture.url + '/' + this.name, maxX, texture.width);
+ cc.errorID(3300, texture.nativeUrl + '/' + this.name, maxX, texture.width);
}
if (maxY > texture.height) {
- cc.errorID(3400, texture.url + '/' + this.name, maxY, texture.height);
+ cc.errorID(3400, texture.nativeUrl + '/' + this.name, maxY, texture.height);
+ }
+ },
+
+ _flipXY (uvs) {
+ if (this._flipX) {
+ let tempVal = uvs[0];
+ uvs[0] = uvs[1];
+ uvs[1] = tempVal;
+
+ tempVal = uvs[2];
+ uvs[2] = uvs[3];
+ uvs[3] = tempVal;
+ }
+
+ if (this._flipY) {
+ let tempVal = uvs[0];
+ uvs[0] = uvs[2];
+ uvs[2] = tempVal;
+
+ tempVal = uvs[1];
+ uvs[1] = uvs[3];
+ uvs[3] = tempVal;
}
},
@@ -544,6 +591,8 @@ let SpriteFrame = cc.Class(/** @lends cc.SpriteFrame# */{
temp_uvs[1].v = (rect.y + leftWidth + centerWidth) / atlasHeight;
temp_uvs[0].v = (rect.y + rect.width) / atlasHeight;
+ this._flipXY(temp_uvs);
+
for (let row = 0; row < 4; ++row) {
let rowD = temp_uvs[row];
for (let col = 0; col < 4; ++col) {
@@ -565,6 +614,8 @@ let SpriteFrame = cc.Class(/** @lends cc.SpriteFrame# */{
temp_uvs[1].v = (rect.y + topHeight + centerHeight) / atlasHeight;
temp_uvs[0].v = (rect.y + rect.height) / atlasHeight;
+ this._flipXY(temp_uvs);
+
for (let row = 0; row < 4; ++row) {
let rowD = temp_uvs[row];
for (let col = 0; col < 4; ++col) {
@@ -578,6 +629,30 @@ let SpriteFrame = cc.Class(/** @lends cc.SpriteFrame# */{
}
},
+ _setDynamicAtlasFrame (frame) {
+ if (!frame) return;
+
+ this._original = {
+ _texture : this._texture,
+ _x : this._rect.x,
+ _y : this._rect.y
+ }
+
+ this._texture = frame.texture;
+ this._rect.x = frame.x;
+ this._rect.y = frame.y;
+ this._calculateUV();
+ },
+
+ _resetDynamicAtlasFrame () {
+ if (!this._original) return;
+ this._rect.x = this._original._x;
+ this._rect.y = this._original._y;
+ this._texture = this._original._texture;
+ this._original = null;
+ this._calculateUV();
+ },
+
_calculateUV () {
let rect = this._rect,
texture = this._texture,
@@ -614,6 +689,42 @@ let SpriteFrame = cc.Class(/** @lends cc.SpriteFrame# */{
uv[7] = t;
}
+ if (this._flipX) {
+ let tempVal = uv[0];
+ uv[0] = uv[2];
+ uv[2] = tempVal;
+
+ tempVal = uv[1];
+ uv[1] = uv[3];
+ uv[3] = tempVal;
+
+ tempVal = uv[4];
+ uv[4] = uv[6];
+ uv[6] = tempVal;
+
+ tempVal = uv[5];
+ uv[5] = uv[7];
+ uv[7] = tempVal;
+ }
+
+ if (this._flipY) {
+ let tempVal = uv[0];
+ uv[0] = uv[4];
+ uv[4] = tempVal;
+
+ tempVal = uv[1];
+ uv[1] = uv[5];
+ uv[5] = tempVal;
+
+ tempVal = uv[2];
+ uv[2] = uv[6];
+ uv[6] = tempVal;
+
+ tempVal = uv[3];
+ uv[3] = uv[7];
+ uv[7] = tempVal;
+ }
+
let vertices = this.vertices;
if (vertices) {
vertices.nu.length = 0;
@@ -629,7 +740,7 @@ let SpriteFrame = cc.Class(/** @lends cc.SpriteFrame# */{
// SERIALIZATION
- _serialize: CC_EDITOR && function (exporting) {
+ _serialize: (CC_EDITOR || CC_TEST) && function (exporting, ctx) {
let rect = this._rect;
let offset = this._offset;
let size = this._originalSize;
@@ -646,6 +757,7 @@ let SpriteFrame = cc.Class(/** @lends cc.SpriteFrame# */{
}
if (uuid && exporting) {
uuid = Editor.Utils.UuidUtils.compressUuid(uuid, true);
+ ctx.dependsOn('_textureSetter', uuid);
}
let vertices;
@@ -661,7 +773,7 @@ let SpriteFrame = cc.Class(/** @lends cc.SpriteFrame# */{
return {
name: this._name,
- texture: uuid || undefined,
+ texture: (!exporting && uuid) || undefined,
atlas: exporting ? undefined : this._atlasUuid, // strip from json if exporting
rect: rect ? [rect.x, rect.y, rect.width, rect.height] : undefined,
offset: offset ? [offset.x, offset.y] : undefined,
@@ -675,7 +787,7 @@ let SpriteFrame = cc.Class(/** @lends cc.SpriteFrame# */{
_deserialize: function (data, handle) {
let rect = data.rect;
if (rect) {
- this.setRect(new cc.Rect(rect[0], rect[1], rect[2], rect[3]));
+ this._rect = new cc.Rect(rect[0], rect[1], rect[2], rect[3]);
}
if (data.offset) {
this.setOffset(new cc.Vec2(data.offset[0], data.offset[1]));
@@ -705,10 +817,12 @@ let SpriteFrame = cc.Class(/** @lends cc.SpriteFrame# */{
this.vertices.nv = [];
}
- // load texture via _textureSetter
- let textureUuid = data.texture;
- if (textureUuid) {
- handle.result.push(this, '_textureSetter', textureUuid);
+ if (!CC_BUILD) {
+ // manually load texture via _textureSetter
+ let textureUuid = data.texture;
+ if (textureUuid) {
+ handle.result.push(this, '_textureSetter', textureUuid);
+ }
}
}
});
diff --git a/cocos2d/core/assets/CCTTFFont.js b/cocos2d/core/assets/CCTTFFont.js
index f93bb60d3d6..01805958b9b 100644
--- a/cocos2d/core/assets/CCTTFFont.js
+++ b/cocos2d/core/assets/CCTTFFont.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -51,6 +51,13 @@ var TTFFont = cc.Class({
this._fontFamily = value || 'Arial';
},
override: true
+ },
+
+ _nativeDep: {
+ get () {
+ return { uuid: this._uuid, __nativeName__: this._native, ext: cc.path.extname(this._native), __isNative__: true };
+ },
+ override: true
}
}
});
diff --git a/cocos2d/core/assets/CCTextAsset.js b/cocos2d/core/assets/CCTextAsset.js
index 385346ee159..dfa6c9f2df2 100644
--- a/cocos2d/core/assets/CCTextAsset.js
+++ b/cocos2d/core/assets/CCTextAsset.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/assets/CCTexture2D.js b/cocos2d/core/assets/CCTexture2D.js
index 50a13d20e5b..38635383ae9 100644
--- a/cocos2d/core/assets/CCTexture2D.js
+++ b/cocos2d/core/assets/CCTexture2D.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -25,22 +25,24 @@
****************************************************************************/
const EventTarget = require('../event/event-target');
-const renderEngine = require('../renderer/render-engine');
const renderer = require('../renderer');
require('../platform/CCClass');
-const gfx = renderEngine.gfx;
+
+import gfx from '../../renderer/gfx';
const GL_NEAREST = 9728; // gl.NEAREST
const GL_LINEAR = 9729; // gl.LINEAR
const GL_REPEAT = 10497; // gl.REPEAT
const GL_CLAMP_TO_EDGE = 33071; // gl.CLAMP_TO_EDGE
const GL_MIRRORED_REPEAT = 33648; // gl.MIRRORED_REPEAT
+const GL_RGBA = 6408; // gl.RGBA
const CHAR_CODE_0 = 48; // '0'
const CHAR_CODE_1 = 49; // '1'
var idGenerater = new (require('../platform/id-generater'))('Tex');
+
/**
*
* This class allows to easily create OpenGL or Canvas 2D textures from images, text or raw data.
@@ -54,6 +56,9 @@ var idGenerater = new (require('../platform/id-generater'))('Tex');
* @extends Asset
*/
+// define a specified number for the pixel format which gfx do not have a standard definition.
+let CUSTOM_PIXEL_FORMAT = 1024;
+
/**
* The texture pixel format, default value is RGBA8888,
* you should note that textures loaded by normal image files (png, jpg) can only support RGBA8888 format,
@@ -139,6 +144,15 @@ const PixelFormat = cc.Enum({
* @type {Number}
*/
RGBA_PVRTC_2BPPV1: gfx.TEXTURE_FMT_RGBA_PVRTC_2BPPV1,
+ /**
+ * rgb separate a 2 bpp pvrtc
+ * RGB_A_PVRTC_2BPPV1 texture is a 2x height RGB_PVRTC_2BPPV1 format texture.
+ * It separate the origin alpha channel to the bottom half atlas, the origin rgb channel to the top half atlas
+ * @property RGB_A_PVRTC_2BPPV1
+ * @readonly
+ * @type {Number}
+ */
+ RGB_A_PVRTC_2BPPV1: CUSTOM_PIXEL_FORMAT++,
/**
* rgb 4 bpp pvrtc
* @property RGB_PVRTC_4BPPV1
@@ -153,6 +167,44 @@ const PixelFormat = cc.Enum({
* @type {Number}
*/
RGBA_PVRTC_4BPPV1: gfx.TEXTURE_FMT_RGBA_PVRTC_4BPPV1,
+ /**
+ * rgb a 4 bpp pvrtc
+ * RGB_A_PVRTC_4BPPV1 texture is a 2x height RGB_PVRTC_4BPPV1 format texture.
+ * It separate the origin alpha channel to the bottom half atlas, the origin rgb channel to the top half atlas
+ * @property RGB_A_PVRTC_4BPPV1
+ * @readonly
+ * @type {Number}
+ */
+ RGB_A_PVRTC_4BPPV1: CUSTOM_PIXEL_FORMAT++,
+ /**
+ * rgb etc1
+ * @property RGB_ETC1
+ * @readonly
+ * @type {Number}
+ */
+ RGB_ETC1: gfx.TEXTURE_FMT_RGB_ETC1,
+ /**
+ * rgba etc1
+ * @property RGBA_ETC1
+ * @readonly
+ * @type {Number}
+ */
+ RGBA_ETC1: CUSTOM_PIXEL_FORMAT++,
+
+ /**
+ * rgb etc2
+ * @property RGB_ETC2
+ * @readonly
+ * @type {Number}
+ */
+ RGB_ETC2: gfx.TEXTURE_FMT_RGB_ETC2,
+ /**
+ * rgba etc2
+ * @property RGBA_ETC2
+ * @readonly
+ * @type {Number}
+ */
+ RGBA_ETC2: gfx.TEXTURE_FMT_RGBA_ETC2,
});
/**
@@ -218,7 +270,7 @@ let _sharedOpts = {
wrapS: undefined,
wrapT: undefined,
format: undefined,
- mipmap: undefined,
+ genMipmaps: undefined,
images: undefined,
image: undefined,
flipY: undefined,
@@ -230,7 +282,6 @@ function _getSharedOptions () {
}
_images.length = 0;
_sharedOpts.images = _images;
- _sharedOpts.flipY = false;
return _sharedOpts;
}
@@ -262,43 +313,127 @@ var Texture2D = cc.Class({
},
override: true
},
- _hasMipmap: false,
_format: PixelFormat.RGBA8888,
_premultiplyAlpha: false,
_flipY: false,
_minFilter: Filter.LINEAR,
_magFilter: Filter.LINEAR,
+ _mipFilter: Filter.LINEAR,
_wrapS: WrapMode.CLAMP_TO_EDGE,
- _wrapT: WrapMode.CLAMP_TO_EDGE
+ _wrapT: WrapMode.CLAMP_TO_EDGE,
+
+ _isAlphaAtlas: false,
+
+ _genMipmaps: false,
+ /**
+ * !#en Sets whether generate mipmaps for the texture
+ * !#zh 是否为纹理设置生成 mipmaps。
+ * @property {Boolean} genMipmaps
+ * @default false
+ */
+ genMipmaps: {
+ get () {
+ return this._genMipmaps;
+ },
+ set (genMipmaps) {
+ if (this._genMipmaps !== genMipmaps) {
+ var opts = _getSharedOptions();
+ opts.genMipmaps = genMipmaps;
+ this.update(opts);
+ }
+ }
+ },
+
+ _packable: true,
+ /**
+ * !#en
+ * Sets whether texture can be packed into texture atlas.
+ * If need use texture uv in custom Effect, please sets packable to false.
+ * !#zh
+ * 设置纹理是否允许参与合图。
+ * 如果需要在自定义 Effect 中使用纹理 UV,需要禁止该选项。
+ * @property {Boolean} packable
+ * @default true
+ */
+ packable: {
+ get () {
+ return this._packable;
+ },
+ set (val) {
+ this._packable = val;
+ }
+ },
+
+ _nativeDep: {
+ get () {
+ return {
+ __isNative__: true,
+ uuid: this._uuid,
+ ext: this._native,
+ __flipY__: this._flipY,
+ __premultiplyAlpha__: this._premultiplyAlpha
+ };
+ },
+ override: true
+ }
},
statics: {
PixelFormat: PixelFormat,
WrapMode: WrapMode,
Filter: Filter,
+ _FilterIndex: FilterIndex,
// predefined most common extnames
- extnames: ['.png', '.jpg', '.jpeg', '.bmp', '.webp', '.pvr', '.etc'],
+ extnames: ['.png', '.jpg', '.jpeg', '.bmp', '.webp', '.pvr', '.pkm'],
+
+ _parseExt (extIdStr, defaultFormat) {
+ let device = cc.renderer.device;
+ let extIds = extIdStr.split('_');
+
+ let defaultExt = '';
+ let bestExt = '';
+ let bestIndex = 999;
+ let bestFormat = defaultFormat;
+ let SupportTextureFormats = cc.macro.SUPPORT_TEXTURE_FORMATS;
+ for (let i = 0; i < extIds.length; i++) {
+ let extFormat = extIds[i].split('@');
+ let tmpExt = extFormat[0];
+ tmpExt = Texture2D.extnames[tmpExt.charCodeAt(0) - CHAR_CODE_0] || tmpExt;
+
+ let index = SupportTextureFormats.indexOf(tmpExt);
+ if (index !== -1 && index < bestIndex) {
+
+ let tmpFormat = extFormat[1] ? parseInt(extFormat[1]) : defaultFormat;
- _isCompressed (texture) {
- return texture._format >= PixelFormat.RGB_PVRTC_2BPPV1 && texture._format <= PixelFormat.RGBA_PVRTC_4BPPV1;
+ // check whether or not support compressed texture
+ if ( tmpExt === '.pvr' && !device.ext('WEBGL_compressed_texture_pvrtc')) {
+ continue;
+ }
+ else if ((tmpFormat === PixelFormat.RGB_ETC1 || tmpFormat === PixelFormat.RGBA_ETC1) && !device.ext('WEBGL_compressed_texture_etc1')) {
+ continue;
+ }
+ else if ((tmpFormat === PixelFormat.RGB_ETC2 || tmpFormat === PixelFormat.RGBA_ETC2) && !device.ext('WEBGL_compressed_texture_etc')) {
+ continue;
+ }
+ else if (tmpExt === '.webp' && !cc.sys.capabilities.webp) {
+ continue;
+ }
+
+ bestIndex = index;
+ bestExt = tmpExt;
+ bestFormat = tmpFormat;
+ }
+ else if (!defaultExt) {
+ defaultExt = tmpExt;
+ }
+ }
+ return { bestExt, bestFormat, defaultExt };
}
},
ctor () {
// Id for generate hash in material
this._id = idGenerater.getNewId();
-
- /**
- * !#en
- * The url of the texture, this could be empty if the texture wasn't created via a file.
- * !#zh
- * 贴图文件的 url,当贴图不是由文件创建时值可能为空
- * @property url
- * @type {String}
- * @readonly
- */
- // TODO - use nativeUrl directly
- this.url = "";
/**
* !#en
@@ -328,6 +463,8 @@ var Texture2D = cc.Class({
*/
this.height = 0;
+ this._hashDirty = true;
+ this._hash = 0;
this._texture = null;
if (CC_EDITOR) {
@@ -338,11 +475,12 @@ var Texture2D = cc.Class({
/**
* !#en
* Get renderer texture implementation object
- * extended from renderEngine.TextureAsset
+ * extended from render.Texture2D
* !#zh 返回渲染器内部贴图对象
* @method getImpl
*/
getImpl () {
+ if (!this._texture) this._texture = new renderer.Texture2D(renderer.device, {});
return this._texture;
},
@@ -351,7 +489,7 @@ var Texture2D = cc.Class({
},
toString () {
- return this.url || '';
+ return this.nativeUrl || '';
},
/**
@@ -360,7 +498,7 @@ var Texture2D = cc.Class({
* @method update
* @param {Object} options
* @param {DOMImageElement} options.image
- * @param {Boolean} options.mipmap
+ * @param {Boolean} options.genMipmaps
* @param {PixelFormat} options.format
* @param {Filter} options.minFilter
* @param {Filter} options.magFilter
@@ -385,6 +523,10 @@ var Texture2D = cc.Class({
this._magFilter = options.magFilter;
options.magFilter = FilterIndex[options.magFilter];
}
+ if (options.mipFilter !== undefined) {
+ this._mipFilter = options.mipFilter;
+ options.mipFilter = FilterIndex[options.mipFilter];
+ }
if (options.wrapS !== undefined) {
this._wrapS = options.wrapS;
}
@@ -402,30 +544,41 @@ var Texture2D = cc.Class({
this._premultiplyAlpha = options.premultiplyAlpha;
updateImg = true;
}
- if (options.mipmap !== undefined) {
- this._hasMipmap = options.mipmap;
+ if (options.genMipmaps !== undefined) {
+ this._genMipmaps = options.genMipmaps;
}
- if (updateImg && this._image) {
- options.image = this._image;
+ if (cc.sys.capabilities.imageBitmap && this._image instanceof ImageBitmap) {
+ this._checkImageBitmap(this._upload.bind(this, options, updateImg));
}
- if (options.images && options.images.length > 0) {
- this._image = options.images[0];
- }
- else if (options.image !== undefined) {
- this._image = options.image;
- if (!options.images) {
- _images.length = 0;
- options.images = _images;
- }
- // webgl texture 2d uses images
- options.images.push(options.image);
+ else {
+ this._upload(options, updateImg);
}
+
+ }
+ },
+
- if (options.images && options.images.length > 0) {
- this._texture.update(options);
+ _upload (options, updateImg) {
+ if (updateImg && this._image) {
+ options.image = this._image;
+ }
+ if (options.images && options.images.length > 0) {
+ this._image = options.images[0];
+ }
+ else if (options.image !== undefined) {
+ this._image = options.image;
+ if (!options.images) {
+ _images.length = 0;
+ options.images = _images;
}
+ // webgl texture 2d uses images
+ options.images.push(options.image);
}
+
+ this._texture && this._texture.update(options);
+
+ this._hashDirty = true;
},
/**
@@ -443,9 +596,12 @@ var Texture2D = cc.Class({
if (!element)
return;
this._image = element;
- if (CC_WECHATGAME || CC_QQPLAY || element.complete || element instanceof HTMLCanvasElement) {
+ if (element.complete || element instanceof HTMLCanvasElement) {
this.handleLoadedTexture();
}
+ else if (cc.sys.capabilities.imageBitmap && element instanceof ImageBitmap) {
+ this._checkImageBitmap(this.handleLoadedTexture.bind(this));
+ }
else {
var self = this;
element.addEventListener('load', function () {
@@ -459,10 +615,10 @@ var Texture2D = cc.Class({
/**
* !#en
- * Intializes with a texture2d with data in Uint8Array.
- * !#zh 使用一个存储在 Unit8Array 中的图像数据(raw data)初始化数据。
+ * Intializes with texture data in ArrayBufferView.
+ * !#zh 使用一个存储在 ArrayBufferView 中的图像数据(raw data)初始化数据。
* @method initWithData
- * @param {TypedArray} data
+ * @param {ArrayBufferView} data
* @param {Number} pixelFormat
* @param {Number} pixelsWidth
* @param {Number} pixelsHeight
@@ -473,14 +629,14 @@ var Texture2D = cc.Class({
opts.image = data;
// webgl texture 2d uses images
opts.images = [opts.image];
- opts.hasMipmap = this._hasMipmap;
+ opts.genMipmaps = this._genMipmaps;
opts.premultiplyAlpha = this._premultiplyAlpha;
opts.flipY = this._flipY;
opts.minFilter = FilterIndex[this._minFilter];
opts.magFilter = FilterIndex[this._magFilter];
opts.wrapS = this._wrapS;
opts.wrapT = this._wrapT;
- opts.format = pixelFormat;
+ opts.format = this._getGFXPixelFormat(pixelFormat);
opts.width = pixelsWidth;
opts.height = pixelsHeight;
if (!this._texture) {
@@ -491,6 +647,10 @@ var Texture2D = cc.Class({
}
this.width = pixelsWidth;
this.height = pixelsHeight;
+
+ this._updateFormat();
+ this._checkPackable();
+
this.loaded = true;
this.emit("load");
return true;
@@ -498,8 +658,12 @@ var Texture2D = cc.Class({
/**
* !#en
- * HTMLElement Object getter, available only on web.
- * !#zh 获取当前贴图对应的 HTML Image 或 Canvas 对象,只在 Web 平台下有效。
+ * HTMLElement Object getter, available only on web.
+ * Note: texture is packed into texture atlas by default
+ * you should set texture.packable as false before getting Html element object.
+ * !#zh 获取当前贴图对应的 HTML Image 或 Canvas 对象,只在 Web 平台下有效。
+ * 注意:
+ * texture 默认参与动态合图,如果需要获取到正确的 Html 元素对象,需要先设置 texture.packable 为 false
* @method getHtmlElementObj
* @return {HTMLImageElement|HTMLCanvasElement}
*/
@@ -510,7 +674,7 @@ var Texture2D = cc.Class({
/**
* !#en
* Destory this texture and immediately release its video memory. (Inherit from cc.Object.destroy)
- * After destroy, this object is not usable any more.
+ * After destroy, this object is not usable anymore.
* You can use cc.isValid(obj) to check whether the object is destroyed before accessing it.
* !#zh
* 销毁该贴图,并立即释放它对应的显存。(继承自 cc.Object.destroy)
@@ -519,10 +683,13 @@ var Texture2D = cc.Class({
* @return {Boolean} inherit from the CCObject
*/
destroy () {
+ if (cc.sys.capabilities.imageBitmap && this._image instanceof ImageBitmap) {
+ this._image.close && this._image.close();
+ }
+ this._packable && cc.dynamicAtlasManager && cc.dynamicAtlasManager.deleteAtlasTexture(this);
+
this._image = null;
this._texture && this._texture.destroy();
- // TODO cc.textureUtil ?
- // cc.textureCache.removeTextureForKey(this.url); // item.rawUrl || item.url
this._super();
},
@@ -549,15 +716,8 @@ var Texture2D = cc.Class({
return this._premultiplyAlpha || false;
},
- /**
- * !#en
- * Whether or not use mipmap.
- * !#zh 检查问题在上传 GPU 时是否生成 mipmap。
- * @method hasMipmap
- * @return {Boolean}
- */
- hasMipmap () {
- return this._hasMipmap || false;
+ isAlphaAtlas () {
+ return this._isAlphaAtlas;
},
/**
@@ -580,8 +740,8 @@ var Texture2D = cc.Class({
opts.images = [opts.image];
opts.width = this.width;
opts.height = this.height;
- opts.hasMipmap = this._hasMipmap;
- opts.format = this._format;
+ opts.genMipmaps = this._genMipmaps;
+ opts.format = this._getGFXPixelFormat(this._format);
opts.premultiplyAlpha = this._premultiplyAlpha;
opts.flipY = this._flipY;
opts.minFilter = FilterIndex[this._minFilter];
@@ -596,16 +756,20 @@ var Texture2D = cc.Class({
this._texture.update(opts);
}
+ this._updateFormat();
+ this._checkPackable();
+
//dispatch load event to listener.
this.loaded = true;
this.emit("load");
- if (cc.macro.CLEANUP_IMAGE_CACHE && this._image instanceof HTMLImageElement) {
- // wechat game platform will cache image parsed data,
- // so image will consume much more memory than web, releasing it
- this._image.src = "";
- // Release image in loader cache
- cc.loader.removeItem(this._image.id);
+ if (cc.macro.CLEANUP_IMAGE_CACHE) {
+ if (this._image instanceof HTMLImageElement) {
+ this._clearImage();
+ }
+ else if (cc.sys.capabilities.imageBitmap && this._image instanceof ImageBitmap) {
+ this._image.close && this._image.close();
+ }
}
},
@@ -617,7 +781,7 @@ var Texture2D = cc.Class({
* @returns {String}
*/
description () {
- return "";
+ return "";
},
/**
@@ -637,7 +801,7 @@ var Texture2D = cc.Class({
* If the texture size is NPOT (non power of 2), then in can only use gl.CLAMP_TO_EDGE in gl.TEXTURE_WRAP_{S,T}.
* !#zh 设置纹理包装模式。
* 若纹理贴图尺寸是 NPOT(non power of 2),则只能使用 Texture2D.WrapMode.CLAMP_TO_EDGE。
- * @method setTexParameters
+ * @method setWrapMode
* @param {Texture2D.WrapMode} wrapS
* @param {Texture2D.WrapMode} wrapT
*/
@@ -677,6 +841,7 @@ var Texture2D = cc.Class({
if (this._flipY !== flipY) {
var opts = _getSharedOptions();
opts.flipY = flipY;
+ opts.premultiplyAlpha = this._premultiplyAlpha;
this.update(opts);
}
},
@@ -691,23 +856,78 @@ var Texture2D = cc.Class({
setPremultiplyAlpha (premultiply) {
if (this._premultiplyAlpha !== premultiply) {
var opts = _getSharedOptions();
+ opts.flipY = this._flipY;
opts.premultiplyAlpha = premultiply;
this.update(opts);
}
},
-
- /**
- * !#en
- * Sets whether generate mipmaps for the texture
- * !#zh 是否为纹理设置生成 mipmaps。
- * @method setMipmap
- * @param {Boolean} mipmap
- */
- setMipmap (mipmap) {
- if (this._hasMipmap !== mipmap) {
- var opts = _getSharedOptions();
- opts.hasMipmap = mipmap;
- this.update(opts);
+
+ _updateFormat () {
+ this._isAlphaAtlas = this._format === PixelFormat.RGBA_ETC1 || this._format === PixelFormat.RGB_A_PVRTC_4BPPV1 || this._format === PixelFormat.RGB_A_PVRTC_2BPPV1;
+ if (CC_JSB) {
+ this._texture.setAlphaAtlas(this._isAlphaAtlas);
+ }
+ },
+
+ _checkPackable () {
+ let dynamicAtlas = cc.dynamicAtlasManager;
+ if (!dynamicAtlas) return;
+
+ if (this._isCompressed()) {
+ this._packable = false;
+ return;
+ }
+
+ let w = this.width, h = this.height;
+ if (!this._image ||
+ w > dynamicAtlas.maxFrameSize || h > dynamicAtlas.maxFrameSize ||
+ this._getHash() !== dynamicAtlas.Atlas.DEFAULT_HASH) {
+ this._packable = false;
+ return;
+ }
+
+ if (this._image && this._image instanceof HTMLCanvasElement) {
+ this._packable = true;
+ }
+ },
+
+ _getOpts() {
+ let opts = _getSharedOptions();
+ opts.width = this.width;
+ opts.height = this.height;
+ opts.genMipmaps = this._genMipmaps;
+ opts.format = this._format;
+ opts.premultiplyAlpha = this._premultiplyAlpha;
+ opts.anisotropy = this._anisotropy;
+ opts.flipY = this._flipY;
+ opts.minFilter = FilterIndex[this._minFilter];
+ opts.magFilter = FilterIndex[this._magFilter];
+ opts.mipFilter = FilterIndex[this._mipFilter];
+ opts.wrapS = this._wrapS;
+ opts.wrapT = this._wrapT;
+ return opts;
+ },
+
+ _getGFXPixelFormat (format) {
+ if (format === PixelFormat.RGBA_ETC1) {
+ format = PixelFormat.RGB_ETC1;
+ }
+ else if (format === PixelFormat.RGB_A_PVRTC_4BPPV1) {
+ format = PixelFormat.RGB_PVRTC_4BPPV1;
+ }
+ else if (format === PixelFormat.RGB_A_PVRTC_2BPPV1) {
+ format = PixelFormat.RGB_PVRTC_2BPPV1;
+ }
+ return format;
+ },
+
+ _resetUnderlyingMipmaps(mipmapSources) {
+ const opts = this._getOpts();
+ opts.images = mipmapSources || [null];
+ if (!this._texture) {
+ this._texture = new renderer.Texture2D(renderer.device, opts);
+ } else {
+ this._texture.update(opts);
}
},
@@ -723,7 +943,7 @@ var Texture2D = cc.Class({
let exts = [];
for (let i = 0; i < exportedExts.length; i++) {
let extId = "";
- let ext = exportedExts[i]
+ let ext = exportedExts[i];
if (ext) {
// ext@format
let extFormat = ext.split('@');
@@ -739,53 +959,31 @@ var Texture2D = cc.Class({
}
extId = exts.join('_');
}
- let asset = "" + extId + "," +
- this._minFilter + "," + this._magFilter + "," +
- this._wrapS + "," + this._wrapT + "," +
- (this._premultiplyAlpha ? 1 : 0);
+ let asset = `${extId},${this._minFilter},${this._magFilter},${this._wrapS},${this._wrapT},` +
+ `${this._premultiplyAlpha ? 1 : 0},${this._genMipmaps ? 1 : 0},${this._packable ? 1 : 0}`;
return asset;
},
- _deserialize: function (data, handle) {
+ _deserialize: function (data) {
let fields = data.split(',');
// decode extname
- var extIdStr = fields[0];
+ let extIdStr = fields[0];
if (extIdStr) {
- let extIds = extIdStr.split('_');
+ var result = Texture2D._parseExt(extIdStr, this._format);
- let extId = 999;
- let ext = '';
- let format = this._format;
- let SupportTextureFormats = cc.macro.SUPPORT_TEXTURE_FORMATS;
- for (let i = 0; i < extIds.length; i++) {
- let extFormat = extIds[i].split('@');
- let tmpExt = extFormat[0];
- tmpExt = tmpExt.charCodeAt(0) - CHAR_CODE_0;
- tmpExt = Texture2D.extnames[tmpExt] || extFormat;
-
- let index = SupportTextureFormats.indexOf(tmpExt);
- if (index !== -1 && index < extId) {
- extId = index;
- ext = tmpExt;
- format = extFormat[1] ? parseInt(extFormat[1]) : this._format;
- }
+ if (result.bestExt) {
+ this._setRawAsset(result.bestExt);
+ this._format = result.bestFormat;
}
-
- if (ext) {
- this._setRawAsset(ext);
- this._format = format;
+ else if (result.defaultExt) {
+ this._setRawAsset(result.defaultExt);
+ cc.warnID(3120, result.defaultExt, result.defaultExt);
}
-
- // preset uuid to get correct nativeUrl
- let loadingItem = handle.customEnv;
- let uuid = loadingItem && loadingItem.uuid;
- if (uuid) {
- this._uuid = uuid;
- var url = this.nativeUrl;
- this.url = url;
+ else {
+ throw new Error(cc.debug.getError(3121));
}
}
- if (fields.length === 6) {
+ if (fields.length === 8) {
// decode filters
this._minFilter = parseInt(fields[1]);
this._magFilter = parseInt(fields[2]);
@@ -794,6 +992,63 @@ var Texture2D = cc.Class({
this._wrapT = parseInt(fields[4]);
// decode premultiply alpha
this._premultiplyAlpha = fields[5].charCodeAt(0) === CHAR_CODE_1;
+ this._genMipmaps = fields[6].charCodeAt(0) === CHAR_CODE_1;
+ this._packable = fields[7].charCodeAt(0) === CHAR_CODE_1;
+ }
+ },
+
+ _getHash () {
+ if (!this._hashDirty) {
+ return this._hash;
+ }
+ let genMipmaps = this._genMipmaps ? 1 : 0;
+ let premultiplyAlpha = this._premultiplyAlpha ? 1 : 0;
+ let flipY = this._flipY ? 1 : 0;
+ let minFilter = this._minFilter === Filter.LINEAR ? 1 : 2;
+ let magFilter = this._magFilter === Filter.LINEAR ? 1 : 2;
+ let wrapS = this._wrapS === WrapMode.REPEAT ? 1 : (this._wrapS === WrapMode.CLAMP_TO_EDGE ? 2 : 3);
+ let wrapT = this._wrapT === WrapMode.REPEAT ? 1 : (this._wrapT === WrapMode.CLAMP_TO_EDGE ? 2 : 3);
+ let pixelFormat = this._format;
+ let image = this._image;
+ if (CC_JSB && image) {
+ if (image._glFormat && image._glFormat !== GL_RGBA)
+ pixelFormat = 0;
+ premultiplyAlpha = image._premultiplyAlpha ? 1 : 0;
+ }
+
+ this._hash = Number(`${minFilter}${magFilter}${pixelFormat}${wrapS}${wrapT}${genMipmaps}${premultiplyAlpha}${flipY}`);
+ this._hashDirty = false;
+ return this._hash;
+ },
+
+ _isCompressed () {
+ return this._format < PixelFormat.A8 || this._format > PixelFormat.RGBA32F;
+ },
+
+ _clearImage () {
+ this._image.src = "";
+ },
+
+ _checkImageBitmap (cb) {
+ let image = this._image;
+ let flipY = this._flipY;
+ let premultiplyAlpha = this._premultiplyAlpha;
+ if (this._flipY !== image.flipY || this._premultiplyAlpha !== image.premultiplyAlpha) {
+ createImageBitmap(image, {
+ imageOrientation: flipY !== image.flipY ? 'flipY' : 'none',
+ premultiplyAlpha: premultiplyAlpha ? 'premultiply' : 'none'}
+ ).then((result) => {
+ image.close && image.close();
+ result.flipY = flipY;
+ result.premultiplyAlpha = premultiplyAlpha;
+ this._image = result;
+ cb();
+ }, (err) => {
+ cc.error(err.message);
+ });
+ }
+ else {
+ cb();
}
}
});
diff --git a/cocos2d/core/assets/index.js b/cocos2d/core/assets/index.js
index ab7d4dc4b55..1a80e7fac6b 100644
--- a/cocos2d/core/assets/index.js
+++ b/cocos2d/core/assets/index.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -24,7 +24,6 @@
THE SOFTWARE.
****************************************************************************/
-require('./CCRawAsset');
require('./CCAsset');
require('./CCFont');
require('./CCPrefab');
@@ -39,4 +38,6 @@ require('./CCSpriteAtlas');
require('./CCBitmapFont');
require('./CCLabelAtlas');
require('./CCTextAsset');
-require('./CCJsonAsset');
\ No newline at end of file
+require('./CCJsonAsset');
+require('./CCBufferAsset');
+require('./material');
diff --git a/cocos2d/core/assets/material/CCEffectAsset.js b/cocos2d/core/assets/material/CCEffectAsset.js
new file mode 100644
index 00000000000..1e882b1c9a2
--- /dev/null
+++ b/cocos2d/core/assets/material/CCEffectAsset.js
@@ -0,0 +1,54 @@
+import Asset from '../CCAsset';
+import { parseEffect } from './effect-parser';
+
+/**
+ * !#en Effect Asset.
+ * !#zh Effect 资源类型。
+ * @class EffectAsset
+ * @extends Asset
+ */
+let EffectAsset = cc.Class({
+ name: 'cc.EffectAsset',
+ extends: Asset,
+
+ ctor () {
+ this._effect = null;
+ },
+
+ properties: {
+ properties: Object,
+ techniques: [],
+ shaders: []
+ },
+
+ onLoad () {
+ if (cc.game.renderType === cc.game.RENDER_TYPE_CANVAS) {
+ return;
+ }
+
+ let lib = cc.renderer._forward._programLib;
+ for (let i = 0; i < this.shaders.length; i++) {
+ lib.define(this.shaders[i]);
+ }
+
+ this._initEffect();
+ },
+
+ _initEffect () {
+ if (this._effect) return;
+ this._effect = parseEffect(this);
+ Object.freeze(this._effect);
+ },
+
+ getInstantiatedEffect () {
+ this._initEffect();
+ return this._effect.clone();
+ },
+
+ getEffect () {
+ this._initEffect();
+ return this._effect;
+ }
+});
+
+module.exports = cc.EffectAsset = EffectAsset;
diff --git a/cocos2d/core/assets/material/CCMaterial.js b/cocos2d/core/assets/material/CCMaterial.js
new file mode 100644
index 00000000000..e0249b31bd2
--- /dev/null
+++ b/cocos2d/core/assets/material/CCMaterial.js
@@ -0,0 +1,408 @@
+/****************************************************************************
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ http://www.cocos.com
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+const Asset = require('../CCAsset');
+const Texture = require('../CCTexture2D');
+const PixelFormat = Texture.PixelFormat;
+const EffectAsset = require('./CCEffectAsset');
+const textureUtil = require('../../utils/texture-util');
+const gfx = cc.gfx;
+
+/**
+ * !#en Material builtin name
+ * !#zh 内置材质名字
+ * @enum Material.BUILTIN_NAME
+ */
+const BUILTIN_NAME = cc.Enum({
+ /**
+ * @property SPRITE
+ * @readonly
+ * @type {String}
+ */
+ SPRITE: '2d-sprite',
+ /**
+ * @property GRAY_SPRITE
+ * @readonly
+ * @type {String}
+ */
+ GRAY_SPRITE: '2d-gray-sprite',
+ /**
+ * @property UNLIT
+ * @readonly
+ * @type {String}
+ */
+ UNLIT: 'unlit',
+});
+
+
+/**
+ * !#en Material Asset.
+ * !#zh 材质资源类。
+ * @class Material
+ * @extends Asset
+ */
+let Material = cc.Class({
+ name: 'cc.Material',
+ extends: Asset,
+
+ ctor () {
+ this.loaded = false;
+ this._manualHash = false;
+ this._dirty = true;
+ this._effect = null;
+ },
+
+ properties: {
+ // deprecated
+ _defines: {
+ default: undefined,
+ type: Object
+ },
+ // deprecated
+ _props: {
+ default: undefined,
+ type: Object
+ },
+
+ _effectAsset: {
+ type: EffectAsset,
+ default: null,
+ },
+
+ _techniqueIndex: 0,
+ _techniqueData: Object,
+
+ effectName: CC_EDITOR ? {
+ get () {
+ return this._effectAsset && this._effectAsset.name;
+ },
+ set (val) {
+ let effectAsset = cc.assetManager.builtins.getBuiltin('effect', val);
+ if (!effectAsset) {
+ Editor.warn(`no effect named '${val}' found`);
+ return;
+ }
+ this.effectAsset = effectAsset;
+ }
+ } : undefined,
+
+ effectAsset: {
+ get () {
+ return this._effectAsset;
+ },
+ set (asset) {
+ if (cc.game.renderType === cc.game.RENDER_TYPE_CANVAS) {
+ return;
+ }
+
+ this._effectAsset = asset;
+ if (!asset) {
+ cc.error('Can not set an empty effect asset.');
+ return;
+ }
+
+ this._effect = this._effectAsset.getInstantiatedEffect();
+ }
+ },
+
+ effect: {
+ get () {
+ return this._effect;
+ }
+ },
+
+ techniqueIndex: {
+ get () {
+ return this._techniqueIndex;
+ },
+ set (v) {
+ this._techniqueIndex = v;
+ this._effect.switchTechnique(v);
+ }
+ }
+ },
+
+ statics: {
+ /**
+ * !#en Get built-in materials
+ * !#zh 获取内置材质
+ * @static
+ * @method getBuiltinMaterial
+ * @param {string} name
+ * @return {Material}
+ */
+ getBuiltinMaterial (name) {
+ if (cc.game.renderType === cc.game.RENDER_TYPE_CANVAS) {
+ return new cc.Material();
+ }
+ return cc.assetManager.builtins.getBuiltin('material', 'builtin-' + name);
+ },
+
+ BUILTIN_NAME,
+
+ /**
+ * !#en Creates a Material with builtin Effect.
+ * !#zh 使用内建 Effect 创建一个材质。
+ * @static
+ * @method createWithBuiltin
+ * @param {string} effectName
+ * @param {number} [techniqueIndex]
+ * @return {Material}
+ */
+ createWithBuiltin (effectName, techniqueIndex = 0) {
+ let effectAsset = cc.assetManager.builtins.getBuiltin('effect', 'builtin-' + effectName);
+ return Material.create(effectAsset, techniqueIndex);
+ },
+ /**
+ * !#en Creates a Material.
+ * !#zh 创建一个材质。
+ * @static
+ * @method create
+ * @param {EffectAsset} effectAsset
+ * @param {number} [techniqueIndex]
+ * @return {Material}
+ */
+ create (effectAsset, techniqueIndex = 0) {
+ if (!effectAsset) return null;
+ let material = new Material();
+ material.effectAsset = effectAsset;
+ material.techniqueIndex = techniqueIndex;
+ return material;
+ }
+ },
+
+ /**
+ * !#en Sets the Material property
+ * !#zh 设置材质的属性
+ * @method setProperty
+ * @param {string} name
+ * @param {Object} val
+ * @param {number} [passIdx]
+ * @param {boolean} [directly]
+ */
+ setProperty (name, val, passIdx, directly) {
+ if (cc.game.renderType === cc.game.RENDER_TYPE_CANVAS) return;
+
+ if (typeof passIdx === 'string') {
+ passIdx = parseInt(passIdx);
+ }
+
+ if (val instanceof Texture) {
+ let isAlphaAtlas = val.isAlphaAtlas();
+ let key = 'CC_USE_ALPHA_ATLAS_' + name;
+ let def = this.getDefine(key, passIdx);
+ if (isAlphaAtlas || def) {
+ this.define(key, isAlphaAtlas);
+ }
+ if (!val.loaded) {
+ cc.assetManager.postLoadNative(val);
+ }
+ }
+
+ this._effect.setProperty(name, val, passIdx, directly);
+ },
+
+ /**
+ * !#en Gets the Material property.
+ * !#zh 获取材质的属性。
+ * @method getProperty
+ * @param {string} name
+ * @param {number} passIdx
+ * @return {Object}
+ */
+ getProperty (name, passIdx) {
+ if (typeof passIdx === 'string') {
+ passIdx = parseInt(passIdx);
+ }
+ return this._effect.getProperty(name, passIdx);
+ },
+
+ /**
+ * !#en Sets the Material define.
+ * !#zh 设置材质的宏定义。
+ * @method define
+ * @param {string} name
+ * @param {boolean|number} val
+ * @param {number} [passIdx]
+ * @param {boolean} [force]
+ */
+ define (name, val, passIdx, force) {
+ if (cc.game.renderType === cc.game.RENDER_TYPE_CANVAS) return;
+
+ if (typeof passIdx === 'string') {
+ passIdx = parseInt(passIdx);
+ }
+ this._effect.define(name, val, passIdx, force);
+ },
+
+ /**
+ * !#en Gets the Material define.
+ * !#zh 获取材质的宏定义。
+ * @method getDefine
+ * @param {string} name
+ * @param {number} [passIdx]
+ * @return {boolean|number}
+ */
+ getDefine (name, passIdx) {
+ if (typeof passIdx === 'string') {
+ passIdx = parseInt(passIdx);
+ }
+ return this._effect.getDefine(name, passIdx);
+ },
+
+ /**
+ * !#en Sets the Material cull mode.
+ * !#zh 设置材质的裁减模式。
+ * @method setCullMode
+ * @param {number} cullMode
+ * @param {number} passIdx
+ */
+ setCullMode (cullMode = gfx.CULL_BACK, passIdx) {
+ this._effect.setCullMode(cullMode, passIdx);
+ },
+
+ /**
+ * !#en Sets the Material depth states.
+ * !#zh 设置材质的深度渲染状态。
+ * @method setDepth
+ * @param {boolean} depthTest
+ * @param {boolean} depthWrite
+ * @param {number} depthFunc
+ * @param {number} passIdx
+ */
+ setDepth (
+ depthTest = false,
+ depthWrite = false,
+ depthFunc = gfx.DS_FUNC_LESS,
+ passIdx
+ ) {
+ this._effect.setDepth(depthTest, depthWrite, depthFunc, passIdx);
+ },
+
+ /**
+ * !#en Sets the Material blend states.
+ * !#zh 设置材质的混合渲染状态。
+ * @method setBlend
+ * @param {boolean} enabled
+ * @param {number} blendEq
+ * @param {number} blendSrc
+ * @param {number} blendDst
+ * @param {number} blendAlphaEq
+ * @param {number} blendSrcAlpha
+ * @param {number} blendDstAlpha
+ * @param {number} blendColor
+ * @param {number} passIdx
+ */
+ setBlend (
+ enabled = false,
+ blendEq = gfx.BLEND_FUNC_ADD,
+ blendSrc = gfx.BLEND_SRC_ALPHA,
+ blendDst = gfx.BLEND_ONE_MINUS_SRC_ALPHA,
+ blendAlphaEq = gfx.BLEND_FUNC_ADD,
+ blendSrcAlpha = gfx.BLEND_SRC_ALPHA,
+ blendDstAlpha = gfx.BLEND_ONE_MINUS_SRC_ALPHA,
+ blendColor = 0xffffffff,
+ passIdx
+ ) {
+ this._effect.setBlend(enabled, blendEq, blendSrc, blendDst, blendAlphaEq, blendSrcAlpha, blendDstAlpha, blendColor, passIdx);
+ },
+
+ /**
+ * !#en Sets whether enable the stencil test.
+ * !#zh 设置是否开启模板测试。
+ * @method setStencilEnabled
+ * @param {number} stencilTest
+ * @param {number} passIdx
+ */
+ setStencilEnabled (stencilTest = gfx.STENCIL_INHERIT, passIdx) {
+ this._effect.setStencilEnabled(stencilTest, passIdx);
+ },
+
+ /**
+ * !#en Sets the Material stencil render states.
+ * !#zh 设置材质的模板测试渲染参数。
+ * @method setStencil
+ * @param {number} stencilTest
+ * @param {number} stencilFunc
+ * @param {number} stencilRef
+ * @param {number} stencilMask
+ * @param {number} stencilFailOp
+ * @param {number} stencilZFailOp
+ * @param {number} stencilZPassOp
+ * @param {number} stencilWriteMask
+ * @param {number} passIdx
+ */
+ setStencil (
+ stencilTest = gfx.STENCIL_INHERIT,
+ stencilFunc = gfx.DS_FUNC_ALWAYS,
+ stencilRef = 0,
+ stencilMask = 0xff,
+ stencilFailOp = gfx.STENCIL_OP_KEEP,
+ stencilZFailOp = gfx.STENCIL_OP_KEEP,
+ stencilZPassOp = gfx.STENCIL_OP_KEEP,
+ stencilWriteMask = 0xff,
+ passIdx
+ ) {
+ this._effect.setStencil(stencilTest, stencilFunc, stencilRef, stencilMask, stencilFailOp, stencilZFailOp, stencilZPassOp, stencilWriteMask, passIdx);
+ },
+
+ updateHash (hash) {
+ this._manualHash = hash;
+ this._effect && this._effect.updateHash(hash);
+ },
+
+ getHash () {
+ return this._manualHash || (this._effect && this._effect.getHash());
+ },
+
+ onLoad () {
+ this.effectAsset = this._effectAsset;
+ if (!this._effect) return;
+
+ if (this._techniqueIndex) {
+ this._effect.switchTechnique(this._techniqueIndex);
+ }
+
+ this._techniqueData = this._techniqueData || {};
+
+ let passDatas = this._techniqueData;
+ for (let index in passDatas) {
+ index = parseInt(index);
+ let passData = passDatas[index];
+ if (!passData) continue;
+
+ for (let def in passData.defines) {
+ this.define(def, passData.defines[def], index);
+ }
+ for (let prop in passData.props) {
+ this.setProperty(prop, passData.props[prop], index);
+ }
+ }
+
+ },
+});
+
+export default Material;
+cc.Material = Material;
diff --git a/cocos2d/core/assets/material/effect-base.ts b/cocos2d/core/assets/material/effect-base.ts
new file mode 100644
index 00000000000..465b453d2c7
--- /dev/null
+++ b/cocos2d/core/assets/material/effect-base.ts
@@ -0,0 +1,188 @@
+import Pass from '../../../renderer/core/pass';
+
+const gfx = cc.gfx;
+
+export default class EffectBase {
+ _dirty = true;
+
+ _name = '';
+ get name () {
+ return this._name;
+ }
+
+ _technique = null;
+ get technique () {
+ return this._technique;
+ }
+
+ get passes (): Pass[] {
+ return [];
+ }
+
+ _createPassProp (name, pass) {
+ let prop = pass._properties[name];
+ if (!prop) {
+ return;
+ }
+
+ let uniform = Object.create(null);
+ uniform.name = name;
+ uniform.type = prop.type;
+ if (prop.value instanceof Float32Array) {
+ uniform.value = new Float32Array(prop.value);
+ }
+ else {
+ uniform.value = prop.value;
+ }
+ pass._properties[name] = uniform;
+
+ return uniform;
+ }
+
+ _setPassProperty (name, value, pass, directly) {
+ let properties = pass._properties;
+ let uniform = properties.hasOwnProperty(name);
+ if (!uniform) {
+ uniform = this._createPassProp(name, pass);
+ }
+ else if (uniform.value === value) return;
+
+ this._dirty = true;
+ return Pass.prototype.setProperty.call(pass, name, value, directly);
+ }
+
+ setProperty (name, value, passIdx, directly) {
+ let success = false;
+ let passes = this.passes;
+ let start = 0, end = passes.length;
+ if (passIdx !== undefined) {
+ start = passIdx, end = passIdx + 1;
+ }
+ for (let i = start; i < end; i++) {
+ if (this._setPassProperty(name, value, passes[i], directly)) {
+ success = true;
+ }
+ }
+ if (!success) {
+ cc.warnID(9103, this.name, name);
+ }
+ }
+
+ getProperty (name, passIdx) {
+ let passes = this.passes;
+ if (passIdx >= passes.length) return;
+
+ let start = 0, end = passes.length;
+ if (passIdx !== undefined) {
+ start = passIdx, end = passIdx + 1;
+ }
+ for (let i = start; i < end; i++) {
+ let value = passes[i].getProperty(name);
+ if (value !== undefined) {
+ return value;
+ }
+ }
+ }
+
+ define (name, value, passIdx, force) {
+ let success = false;
+ let passes = this.passes;
+ let start = 0, end = passes.length;
+ if (passIdx !== undefined) {
+ start = passIdx, end = passIdx + 1;
+ }
+ for (let i = start; i < end; i++) {
+ if (passes[i].define(name, value, force)) {
+ success = true;
+ }
+ }
+ if (!success) {
+ cc.warnID(9104, this.name, name);
+ }
+ }
+
+ getDefine (name, passIdx) {
+ let passes = this.passes;
+ if (passIdx >= passes.length) return;
+ let start = 0, end = passes.length;
+ if (passIdx !== undefined) {
+ start = passIdx, end = passIdx + 1;
+ }
+ for (let i = start; i < end; i++) {
+ let value = passes[i].getDefine(name);
+ if (value !== undefined) {
+ return value;
+ }
+ }
+ }
+
+ setCullMode (cullMode = gfx.CULL_BACK, passIdx) {
+ let passes = this.passes;
+ let start = 0, end = passes.length;
+ if (passIdx !== undefined) {
+ start = passIdx, end = passIdx + 1;
+ }
+ for (let i = start; i < end; i++) {
+ passes[i].setCullMode(cullMode);
+ }
+ this._dirty = true;
+ }
+
+ setDepth (depthTest, depthWrite, depthFunc, passIdx) {
+ let passes = this.passes;
+ let start = 0, end = passes.length;
+ if (passIdx !== undefined) {
+ start = passIdx, end = passIdx + 1;
+ }
+ for (let i = start; i < end; i++) {
+ passes[i].setDepth(depthTest, depthWrite, depthFunc);
+ }
+ this._dirty = true;
+ }
+
+ setBlend (enabled, blendEq, blendSrc, blendDst, blendAlphaEq, blendSrcAlpha, blendDstAlpha, blendColor, passIdx) {
+ let passes = this.passes;
+ let start = 0, end = passes.length;
+ if (passIdx !== undefined) {
+ start = passIdx, end = passIdx + 1;
+ }
+ for (let i = start; i < end; i++) {
+ passes[i].setBlend(
+ enabled,
+ blendEq,
+ blendSrc, blendDst,
+ blendAlphaEq,
+ blendSrcAlpha, blendDstAlpha, blendColor
+ );
+ }
+ this._dirty = true;
+ }
+
+ setStencilEnabled (stencilTest = gfx.STENCIL_INHERIT, passIdx) {
+ let passes = this.passes;
+ let start = 0, end = passes.length;
+ if (passIdx !== undefined) {
+ start = passIdx, end = passIdx + 1;
+ }
+ for (let i = start; i < end; i++) {
+ passes[i].setStencilEnabled(stencilTest);
+ }
+ this._dirty = true;
+ }
+
+ setStencil (enabled, stencilFunc, stencilRef, stencilMask, stencilFailOp, stencilZFailOp, stencilZPassOp, stencilWriteMask, passIdx) {
+ let passes = this.passes;
+ let start = 0, end = passes.length;
+ if (passIdx !== undefined) {
+ start = passIdx, end = passIdx + 1;
+ }
+ for (let i = start; i < end; i++) {
+ let pass = passes[i];
+ pass.setStencilFront(enabled, stencilFunc, stencilRef, stencilMask, stencilFailOp, stencilZFailOp, stencilZPassOp, stencilWriteMask);
+ pass.setStencilBack(enabled, stencilFunc, stencilRef, stencilMask, stencilFailOp, stencilZFailOp, stencilZPassOp, stencilWriteMask);
+ }
+ this._dirty = true;
+ }
+}
+
+cc.EffectBase = EffectBase;
diff --git a/cocos2d/core/assets/material/effect-parser.ts b/cocos2d/core/assets/material/effect-parser.ts
new file mode 100644
index 00000000000..5590f72afcd
--- /dev/null
+++ b/cocos2d/core/assets/material/effect-parser.ts
@@ -0,0 +1,152 @@
+import Pass from '../../../renderer/core/pass';
+import { getInspectorProps, enums2default } from '../../../renderer/types';
+import enums from '../../../renderer/enums';
+import Effect from './effect';
+import Technique from '../../../renderer/core/technique';
+
+function getInvolvedProgram (programName) {
+ let lib = cc.renderer._forward._programLib;
+ return lib.getTemplate(programName);
+}
+
+// extract properties from each passes and check whether properties is defined but not used.
+function parseProperties (effectAsset, passJson) {
+ let propertiesJson = passJson.properties || {};
+ let program = getInvolvedProgram(passJson.program);
+
+ // check whether properties are defined in the shaders
+ for (let prop in propertiesJson) {
+ let uniformInfo = program.uniforms.find(u => u.name === prop);
+ // the property is not defined in all the shaders used in techs
+ if (!uniformInfo) {
+ cc.warnID(9107, effectAsset.name, prop);
+ continue;
+ }
+ }
+
+ // create properties
+ let properties = {};
+ program.uniforms.forEach(u => {
+ let name = u.name,
+ prop = properties[name] = Object.assign({}, u),
+ propInfo = propertiesJson[name];
+
+ let value = enums2default[u.type];
+ if (propInfo) {
+ if (propInfo.type === enums.PARAM_TEXTURE_2D) {
+ value = null;
+ }
+ else if (propInfo.type === enums.PARAM_INT || propInfo.type === enums.PARAM_FLOAT) {
+ value = Array.isArray(propInfo.value) ? propInfo.value[0] : propInfo.value;
+ }
+ else {
+ value = new Float32Array(propInfo.value);
+ }
+ }
+ else {
+ value = enums2default[u.type];
+ }
+
+ prop.value = value;
+ });
+
+ return properties;
+};
+
+function passDefines (pass) {
+ let defines = {};
+ let program = getInvolvedProgram(pass.program);
+ program.defines.forEach(d => {
+ defines[d.name] = enums2default[d.type];
+ })
+ return defines;
+}
+
+function parseTechniques (effectAsset) {
+ let techNum = effectAsset.techniques.length;
+ let techniques = new Array(techNum);
+ for (let j = 0; j < techNum; ++j) {
+ let tech = effectAsset.techniques[j];
+ let techName = tech.name || j;
+
+ let passNum = tech.passes.length;
+ let passes = new Array(passNum);
+ for (let k = 0; k < passNum; ++k) {
+ let pass = tech.passes[k];
+
+ let passName = pass.name || k;
+ let detailName = `${effectAsset.name}-${techName}-${passName}`;
+ let stage = pass.stage || 'opaque';
+ let properties = parseProperties(effectAsset, pass);
+ let defines = passDefines(pass);
+
+ let newPass = passes[k] = new Pass(passName, detailName, pass.program, stage, properties, defines);
+
+ // rasterizer state
+ if (pass.rasterizerState) {
+ newPass.setCullMode(pass.rasterizerState.cullMode);
+ }
+
+ // blend state
+ let blendState = pass.blendState && pass.blendState.targets[0];
+ if (blendState) {
+ newPass.setBlend(blendState.blend, blendState.blendEq, blendState.blendSrc,
+ blendState.blendDst, blendState.blendAlphaEq, blendState.blendSrcAlpha, blendState.blendDstAlpha, blendState.blendColor);
+ }
+
+ // depth stencil state
+ let depthStencilState = pass.depthStencilState;
+ if (depthStencilState) {
+ newPass.setDepth(depthStencilState.depthTest, depthStencilState.depthWrite, depthStencilState.depthFunc);
+ newPass.setStencilFront(depthStencilState.stencilTest, depthStencilState.stencilFuncFront, depthStencilState.stencilRefFront, depthStencilState.stencilMaskFront,
+ depthStencilState.stencilFailOpFront, depthStencilState.stencilZFailOpFront, depthStencilState.stencilZPassOpFront, depthStencilState.stencilWriteMaskFront);
+ newPass.setStencilBack(depthStencilState.stencilTest, depthStencilState.stencilFuncBack, depthStencilState.stencilRefBack, depthStencilState.stencilMaskBack,
+ depthStencilState.stencilFailOpBack, depthStencilState.stencilZFailOpBack, depthStencilState.stencilZPassOpBack, depthStencilState.stencilWriteMaskBack);
+ }
+ }
+ techniques[j] = new Technique(techName, passes);
+ }
+
+ return techniques;
+};
+
+export function parseEffect (effect) {
+ let techniques = parseTechniques(effect);
+ return new Effect(effect.name, techniques, 0, effect);
+};
+
+if (CC_EDITOR) {
+ // inspector only need properties defined in CCEffect
+ Effect.parseForInspector = function (effectAsset) {
+ return effectAsset.techniques.map((tech, techIdx) => {
+ let passes = tech.passes.map((pass, passIdx) => {
+ let program = getInvolvedProgram(pass.program);
+
+ let newProps = {};
+ let props = pass.properties;
+ for (let name in props) {
+ newProps[name] = getInspectorProps(props[name]);
+
+ let u = program.uniforms.find(u => u.name === name);
+ newProps[name].defines = u.defines || [];
+ }
+
+ let newDefines = {};
+ program.defines.map(def => {
+ newDefines[def.name] = getInspectorProps(def);
+ })
+
+ return {
+ name: pass.name || passIdx,
+ props: newProps,
+ defines: newDefines,
+ };
+ })
+
+ return {
+ name: tech.name || techIdx,
+ passes: passes,
+ };
+ })
+ };
+}
diff --git a/cocos2d/core/assets/material/effect-variant.ts b/cocos2d/core/assets/material/effect-variant.ts
new file mode 100644
index 00000000000..5623ed1cbf9
--- /dev/null
+++ b/cocos2d/core/assets/material/effect-variant.ts
@@ -0,0 +1,89 @@
+import murmurhash2 from '../../../renderer/murmurhash2_gc';
+import utils from './utils';
+import Pass from '../../../renderer/core/pass';
+import Effect from './effect';
+import EffectBase from './effect-base';
+
+const gfx = cc.gfx;
+
+export default class EffectVariant extends EffectBase {
+ _effect: Effect;
+ _passes: Pass[] = [];
+ _stagePasses = {};
+ _hash = 0;
+
+ get effect () {
+ return this._effect;
+ }
+
+ get name () {
+ return this._effect && (this._effect.name + ' (variant)');
+ }
+
+ get passes () {
+ return this._passes;
+ }
+
+ get stagePasses () {
+ return this._stagePasses;
+ }
+
+ constructor (effect: Effect) {
+ super();
+ this.init(effect);
+ }
+
+ _onEffectChanged () {
+ }
+
+ init (effect: Effect) {
+ if (effect instanceof EffectVariant) {
+ effect = effect.effect;
+ }
+
+ this._effect = effect;
+ this._dirty = true;
+
+ if (effect) {
+ let passes = effect.passes;
+ let variantPasses = this._passes;
+ variantPasses.length = 0;
+ let stagePasses = this._stagePasses = {};
+ for (let i = 0; i < passes.length; i++) {
+ let variant = variantPasses[i] = Object.setPrototypeOf({}, passes[i]);
+ variant._properties = Object.setPrototypeOf({}, passes[i]._properties);
+ variant._defines = Object.setPrototypeOf({}, passes[i]._defines);
+
+ if (!stagePasses[variant._stage]) {
+ stagePasses[variant._stage] = [];
+ }
+ stagePasses[variant._stage].push(variant);
+ }
+ }
+ }
+
+ updateHash (hash: number) {
+
+ }
+
+ getHash () {
+ if (!this._dirty) return this._hash;
+ this._dirty = false;
+
+ let hash = '';
+ hash += utils.serializePasses(this._passes);
+
+ let effect = this._effect;
+ if (effect) {
+ hash += utils.serializePasses(effect.passes);
+ }
+
+ this._hash = murmurhash2(hash, 666);
+
+ this.updateHash(this._hash);
+
+ return this._hash;
+ }
+}
+
+cc.EffectVariant = EffectVariant;
diff --git a/cocos2d/core/assets/material/effect.ts b/cocos2d/core/assets/material/effect.ts
new file mode 100644
index 00000000000..b0327e0e057
--- /dev/null
+++ b/cocos2d/core/assets/material/effect.ts
@@ -0,0 +1,58 @@
+// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+import Technique from '../../../renderer/core/technique';
+import EffectBase from './effect-base';
+
+export default class Effect extends EffectBase {
+
+ _techniques: Technique[] = [];
+ _asset = null;
+
+ get technique () {
+ return this._technique;
+ }
+
+ get passes () {
+ return this._technique.passes;
+ }
+
+ /**
+ * @param {Array} techniques
+ */
+ constructor (name, techniques, techniqueIndex, asset) {
+ super();
+ this.init(name, techniques, techniqueIndex, asset, true);
+ }
+
+ init (name, techniques, techniqueIndex, asset, createNative) {
+ this._name = name;
+ this._techniques = techniques;
+ this._technique = techniques[techniqueIndex];
+ this._asset = asset;
+ }
+
+ switchTechnique (index) {
+ if (index >= this._techniques.length) {
+ cc.warn(`Can not switch to technique with index [${index}]`);
+ return;
+ }
+
+ this._technique = this._techniques[index];
+ }
+
+ clear () {
+ this._techniques = [];
+ }
+
+ clone () {
+ let techniques = [];
+ for (let i = 0; i < this._techniques.length; i++) {
+ techniques.push(this._techniques[i].clone());
+ }
+
+ let techniqueIndex = this._techniques.indexOf(this._technique);
+ return new Effect(this._name, techniques, techniqueIndex, this._asset);
+ }
+}
+
+cc.Effect = Effect;
diff --git a/cocos2d/core/assets/material/index.js b/cocos2d/core/assets/material/index.js
new file mode 100644
index 00000000000..a6c3211443b
--- /dev/null
+++ b/cocos2d/core/assets/material/index.js
@@ -0,0 +1,3 @@
+import './CCEffectAsset';
+import './CCMaterial';
+import './material-variant';
diff --git a/cocos2d/core/assets/material/material-pool.js b/cocos2d/core/assets/material/material-pool.js
new file mode 100644
index 00000000000..8761be3c8fa
--- /dev/null
+++ b/cocos2d/core/assets/material/material-pool.js
@@ -0,0 +1,95 @@
+import utils from './utils';
+import Pool from '../../utils/pool';
+
+/**
+ * {
+ * effectUuid: {
+ * defineSerializeKey: []
+ * }
+ * }
+ */
+class MaterialPool extends Pool {
+ // default disabled material pool
+ enabled = false;
+
+ _pool = {};
+
+ get (exampleMat, renderComponent) {
+ let pool = this._pool;
+
+ if (exampleMat instanceof cc.MaterialVariant) {
+ if (exampleMat._owner) {
+ if (exampleMat._owner === renderComponent) {
+ return exampleMat;
+ }
+ else {
+ exampleMat = exampleMat.material;
+ }
+ }
+ else {
+ exampleMat._owner = renderComponent;
+ return exampleMat;
+ }
+ }
+
+ let instance;
+ if (this.enabled) {
+ let uuid = exampleMat.effectAsset._uuid;
+ if (pool[uuid]) {
+ let key =
+ utils.serializeDefines(exampleMat._effect._defines) +
+ utils.serializeTechniques(exampleMat._effect._techniques);
+ instance = pool[uuid][key] && pool[uuid][key].pop();
+ }
+ }
+
+ if (!instance) {
+ instance = new cc.MaterialVariant(exampleMat);
+ instance._name = exampleMat._name + ' (Instance)';
+ instance._uuid = exampleMat._uuid;
+ }
+ else {
+ this.count--;
+ }
+
+ instance._owner = renderComponent;
+
+ return instance;
+ }
+
+ put (mat) {
+ if (!this.enabled || !mat._owner) {
+ return;
+ }
+
+ let pool = this._pool;
+ let uuid = mat.effectAsset._uuid;
+ if (!pool[uuid]) {
+ pool[uuid] = {};
+ }
+ let key =
+ utils.serializeDefines(mat._effect._defines) +
+ utils.serializeTechniques(mat._effect._techniques);
+ if (!pool[uuid][key]) {
+ pool[uuid][key] = [];
+ }
+ if (this.count > this.maxSize) return;
+
+ this._clean(mat);
+ pool[uuid][key].push(mat);
+ this.count++;
+ }
+
+ clear () {
+ this._pool = {};
+ this.count = 0;
+ }
+
+ _clean (mat) {
+ mat._owner = null;
+ }
+}
+
+let materialPool = new MaterialPool();
+Pool.register('material', materialPool);
+export default materialPool;
diff --git a/cocos2d/core/assets/material/material-variant.ts b/cocos2d/core/assets/material/material-variant.ts
new file mode 100644
index 00000000000..b2066a101bb
--- /dev/null
+++ b/cocos2d/core/assets/material/material-variant.ts
@@ -0,0 +1,73 @@
+
+import Material from './CCMaterial';
+import EffectVariant from './effect-variant';
+import MaterialPool from './material-pool';
+
+let { ccclass, } = cc._decorator;
+
+/**
+ * !#en
+ * Material Variant is an extension of the Material Asset.
+ * Changes to Material Variant do not affect other Material Variant or Material Asset,
+ * and changes to Material Asset are synchronized to the Material Variant.
+ * However, when a Material Variant had already modifies a state, the Material Asset state is not synchronized to the Material Variant.
+ * !#zh
+ * 材质变体是材质资源的一个延伸。
+ * 材质变体的修改不会影响到其他的材质变体或者材质资源,而材质资源的修改会同步体现到材质变体上,
+ * 但是当材质变体对一个状态修改后,材质资源再对这个状态修改是不会同步到材质变体上的。
+ * @class MaterialVariant
+ * @extends Material
+ */
+@ccclass('cc.MaterialVariant')
+export default class MaterialVariant extends Material {
+ _owner: cc.RenderComponent = null;
+ _material: Material = null;
+
+ /**
+ * @method createWithBuiltin
+ * @param {Material.BUILTIN_NAME} materialName
+ * @param {RenderComponent} [owner]
+ * @typescript
+ * static createWithBuiltin (materialName: string, owner: cc.RenderComponent): MaterialVariant | null
+ */
+ static createWithBuiltin (materialName: string, owner: cc.RenderComponent): MaterialVariant | null {
+ return MaterialVariant.create(Material.getBuiltinMaterial(materialName), owner);
+ }
+
+ /**
+ * @method create
+ * @param {Material} material
+ * @param {RenderComponent} [owner]
+ * @typescript
+ * static create (material: Material, owner: cc.RenderComponent): MaterialVariant | null
+ */
+ static create (material: Material, owner: cc.RenderComponent): MaterialVariant | null {
+ if (!material) return null;
+ return MaterialPool.get(material, owner);
+ }
+
+ get uuid () {
+ return this._material._uuid;
+ }
+
+ get owner () {
+ return this._owner;
+ }
+
+ get material () {
+ return this._material;
+ }
+
+ constructor (material: Material) {
+ super();
+ this.init(material);
+ }
+
+ init (material) {
+ this._effect = new EffectVariant(material.effect);
+ this._effectAsset = material._effectAsset;
+ this._material = material;
+ }
+}
+
+cc.MaterialVariant = MaterialVariant;
diff --git a/cocos2d/core/assets/material/utils.js b/cocos2d/core/assets/material/utils.js
new file mode 100644
index 00000000000..56d99038944
--- /dev/null
+++ b/cocos2d/core/assets/material/utils.js
@@ -0,0 +1,85 @@
+// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+import enums from '../../../renderer/enums';
+
+// function genHashCode (str) {
+// var hash = 0;
+// if (str.length == 0) {
+// return hash;
+// }
+// for (var i = 0; i < str.length; i++) {
+// var char = str.charCodeAt(i);
+// hash = ((hash<<5)-hash)+char;
+// hash = hash & hash; // Convert to 32bit integer
+// }
+// return hash;
+// }
+
+function serializeDefines (defines) {
+ let str = '';
+ for (let name in defines) {
+ str += name + defines[name];
+ }
+ return str;
+}
+
+function serializePass (pass, excludeProperties) {
+ let str = pass._programName + pass._cullMode;
+ if (pass._blend) {
+ str += pass._blendEq + pass._blendAlphaEq + pass._blendSrc + pass._blendDst
+ + pass._blendSrcAlpha + pass._blendDstAlpha + pass._blendColor;
+ }
+ if (pass._depthTest) {
+ str += pass._depthWrite + pass._depthFunc;
+ }
+ if (pass._stencilTest) {
+ str += pass._stencilFuncFront + pass._stencilRefFront + pass._stencilMaskFront
+ + pass._stencilFailOpFront + pass._stencilZFailOpFront + pass._stencilZPassOpFront
+ + pass._stencilWriteMaskFront
+ + pass._stencilFuncBack + pass._stencilRefBack + pass._stencilMaskBack
+ + pass._stencilFailOpBack + pass._stencilZFailOpBack + pass._stencilZPassOpBack
+ + pass._stencilWriteMaskBack;
+ }
+
+ if (!excludeProperties) {
+ str += serializeUniforms(pass._properties);
+ }
+ str += serializeDefines(pass._defines);
+
+ return str;
+}
+
+function serializePasses (passes) {
+ let hashData = '';
+ for (let i = 0; i < passes.length; i++) {
+ hashData += serializePass(passes[i]);
+ }
+ return hashData;
+}
+
+function serializeUniforms (uniforms) {
+ let hashData = '';
+ for (let name in uniforms) {
+ let param = uniforms[name];
+ let prop = param.value;
+
+ if (!prop) {
+ continue;
+ }
+
+ if (param.type === enums.PARAM_TEXTURE_2D || param.type === enums.PARAM_TEXTURE_CUBE) {
+ hashData += prop._id + ';';
+ }
+ else {
+ hashData += prop.toString() + ';';
+ }
+ }
+
+ return hashData;
+}
+
+export default {
+ serializeDefines,
+ serializePasses,
+ serializeUniforms
+};
\ No newline at end of file
diff --git a/cocos2d/core/base-ui/CCWidgetManager.js b/cocos2d/core/base-ui/CCWidgetManager.js
index 5bbf5785f83..4065bd114c4 100644
--- a/cocos2d/core/base-ui/CCWidgetManager.js
+++ b/cocos2d/core/base-ui/CCWidgetManager.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -24,7 +24,12 @@
THE SOFTWARE.
****************************************************************************/
-var Event = require('../CCNode').EventType;
+var Event;
+
+// Support serializing widget in asset db, see cocos-creator/2d-tasks/issues/1894
+if (!CC_EDITOR || !Editor.isMainProcess) {
+ Event = require('../CCNode').EventType;
+}
var TOP = 1 << 0;
var MID = 1 << 1; // vertical center
@@ -52,14 +57,13 @@ function getReadonlyNodeSize (parent) {
}
function computeInverseTransForTarget (widgetNode, target, out_inverseTranslate, out_inverseScale) {
- var scaleX = widgetNode._parent._scale.x;
- var scaleY = widgetNode._parent._scale.y;
+ var scaleX = widgetNode._parent.scaleX;
+ var scaleY = widgetNode._parent.scaleY;
var translateX = 0;
var translateY = 0;
for (var node = widgetNode._parent;;) {
- var pos = node._position;
- translateX += pos.x;
- translateY += pos.y;
+ translateX += node.x;
+ translateY += node.y;
node = node._parent; // loop increment
if (!node) {
// ERROR: widgetNode should be child of target
@@ -68,8 +72,8 @@ function computeInverseTransForTarget (widgetNode, target, out_inverseTranslate,
return;
}
if (node !== target) {
- var sx = node._scale.x;
- var sy = node._scale.y;
+ var sx = node.scaleX;
+ var sy = node.scaleY;
translateX *= sx;
translateY *= sy;
scaleX *= sx;
@@ -106,7 +110,7 @@ function align (node, widget) {
var targetAnchor = target._anchorPoint;
var isRoot = !CC_EDITOR && target instanceof cc.Scene;
- var x = node._position.x, y = node._position.y;
+ var x = node.x, y = node.y;
var anchor = node._anchorPoint;
if (widget._alignFlags & HORIZONTAL) {
@@ -132,7 +136,7 @@ function align (node, widget) {
localRight *= inverseScale.x;
}
- var width, anchorX = anchor.x, scaleX = node._scale.x;
+ var width, anchorX = anchor.x, scaleX = node.scaleX;
if (scaleX < 0) {
anchorX = 1.0 - anchorX;
scaleX = -scaleX;
@@ -189,7 +193,7 @@ function align (node, widget) {
localTop *= inverseScale.y;
}
- var height, anchorY = anchor.y, scaleY = node._scale.y;
+ var height, anchorY = anchor.y, scaleY = node.scaleY;
if (scaleY < 0) {
anchorY = 1.0 - anchorY;
scaleY = -scaleY;
@@ -229,18 +233,11 @@ function visitNode (node) {
var widget = node._widget;
if (widget) {
if (CC_DEV) {
- var target = widget._target;
- if (target) {
- var isParent = node !== target && node.isChildOf(target);
- if (!isParent) {
- cc.errorID(6500);
- widget._target = null;
- }
- }
+ widget._validateTargetInDEV();
}
align(node, widget);
if ((!CC_EDITOR || animationState.animatedSinceLastFrame) && widget.alignMode !== AlignMode.ALWAYS) {
- widget.enabled = false;
+ widgetManager.remove(widget);
}
else {
activeWidgets.push(widget);
@@ -277,7 +274,9 @@ function refreshScene () {
let component = cc.engine.getInstanceById(AnimUtils.Cache.component);
if (component) {
let animation = component.getAnimationState(AnimUtils.Cache.animation);
- animationState.time = animation.time;
+ if (animation) {
+ animationState.time = animation.time;
+ }
}
}
else {
@@ -288,7 +287,7 @@ function refreshScene () {
let component = cc.engine.getInstanceById(AnimUtils.Cache.component);
if (component) {
let animation = component.getAnimationState(AnimUtils.Cache.animation);
- if (animationState.time !== animation.time) {
+ if (animation && animationState.time !== animation.time) {
animationState.animatedSinceLastFrame = true;
animationState.time = AnimUtils.Cache.animation.time;
}
@@ -321,7 +320,7 @@ function refreshScene () {
node.isChildOf(editingNode)
) {
// widget contains in activeWidgets should aligned at least once
- widget.enabled = false;
+ widgetManager.remove(widget);
}
else {
align(node, widget);
@@ -440,7 +439,7 @@ function updateAlignment (node) {
}
var widget = node._widget ||
node.getComponent(cc.Widget); // node._widget will be null when widget is disabled
- if (widget) {
+ if (widget && parent) {
align(node, widget);
}
}
@@ -465,12 +464,9 @@ var widgetManager = cc._widgetManager = module.exports = {
cc.engine.on('design-resolution-changed', this.onResized.bind(this));
}
else {
- if (cc.sys.isMobile) {
- window.addEventListener('resize', this.onResized.bind(this));
- }
- else {
- cc.view.on('canvas-resize', this.onResized, this);
- }
+ let thisOnResized = this.onResized.bind(this);
+ cc.view.on('canvas-resize', thisOnResized);
+ window.addEventListener('orientationchange', thisOnResized);
}
},
add: function (widget) {
@@ -497,10 +493,8 @@ var widgetManager = cc._widgetManager = module.exports = {
},
refreshWidgetOnResized (node) {
var widget = cc.Node.isNode(node) && node.getComponent(cc.Widget);
- if (widget) {
- if (widget.alignMode === AlignMode.ON_WINDOW_RESIZE) {
- widget.enabled = true;
- }
+ if (widget && widget.enabled && widget.alignMode === AlignMode.ON_WINDOW_RESIZE) {
+ this.add(widget);
}
var children = node._children;
diff --git a/cocos2d/core/camera/CCCamera.js b/cocos2d/core/camera/CCCamera.js
index 9eb77b30cbe..ae8165b89db 100644
--- a/cocos2d/core/camera/CCCamera.js
+++ b/cocos2d/core/camera/CCCamera.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -24,33 +24,50 @@
THE SOFTWARE.
****************************************************************************/
+import { Mat4, Vec2, Vec3 } from '../value-types';
+import { Ray } from '../geom-utils';
+
const AffineTrans = require('../utils/affine-transform');
-const renderEngine = require('../renderer/render-engine');
const renderer = require('../renderer/index');
+const RenderFlow = require('../renderer/render-flow');
const game = require('../CCGame');
-const mat4 = cc.vmath.mat4;
-const vec2 = cc.vmath.vec2;
-const vec3 = cc.vmath.vec3;
+let RendererCamera = null;
+if (CC_JSB && CC_NATIVERENDERER) {
+ RendererCamera = window.renderer.Camera;
+} else {
+ RendererCamera = require('../../renderer/scene/camera');
+}
+
+let _mat4_temp_1 = cc.mat4();
+let _mat4_temp_2 = cc.mat4();
-let _mat4_temp_1 = mat4.create();
-let _mat4_temp_2 = mat4.create();
-let _vec3_temp_1 = vec3.create();
+let _v3_temp_1 = cc.v3();
+let _v3_temp_2 = cc.v3();
+let _v3_temp_3 = cc.v3();
-let _cameras = [];
+let _cameras = []; // unstable array
+
+function updateMainCamera () {
+ for (let i = 0, minDepth = Number.MAX_VALUE; i < _cameras.length; i++) {
+ let camera = _cameras[i];
+ if (camera._depth < minDepth) {
+ Camera.main = camera;
+ minDepth = camera._depth;
+ }
+ }
+}
let _debugCamera = null;
function repositionDebugCamera () {
if (!_debugCamera) return;
- let node = _debugCamera._node;
- let visibleRect = cc.visibleRect;
- node.z = visibleRect.height / 1.1566;
- node.x = _vec3_temp_1.x = visibleRect.width / 2;
- node.y = _vec3_temp_1.y = visibleRect.height / 2;
- _vec3_temp_1.z = 0;
- node.lookAt(_vec3_temp_1);
+ let node = _debugCamera.getNode();
+ let canvas = cc.game.canvas;
+ node.z = canvas.height / 1.1566;
+ node.x = canvas.width / 2;
+ node.y = canvas.height / 2;
}
/**
@@ -59,11 +76,37 @@ function repositionDebugCamera () {
* @enum Camera.ClearFlags
*/
let ClearFlags = cc.Enum({
+ /**
+ * !#en
+ * Clear the background color.
+ * !#zh
+ * 清除背景颜色
+ * @property COLOR
+ */
COLOR: 1,
+ /**
+ * !#en
+ * Clear the depth buffer.
+ * !#zh
+ * 清除深度缓冲区
+ * @property DEPTH
+ */
DEPTH: 2,
+ /**
+ * !#en
+ * Clear the stencil.
+ * !#zh
+ * 清除模板缓冲区
+ * @property STENCIL
+ */
STENCIL: 4,
});
+let StageFlags = cc.Enum({
+ OPAQUE: 1,
+ TRANSPARENT: 2
+});
+
/**
* !#en
* Camera is usefull when making reel game or other games which need scroll screen.
@@ -77,25 +120,17 @@ let ClearFlags = cc.Enum({
let Camera = cc.Class({
name: 'cc.Camera',
extends: cc.Component,
-
+
ctor () {
if (game.renderType !== game.RENDER_TYPE_CANVAS) {
- let camera = new renderEngine.Camera();
+ let camera = new RendererCamera();
camera.setStages([
- 'transparent'
+ 'opaque',
]);
- this._fov = Math.PI * 60 / 180;
- camera.setFov(this._fov);
- camera.setNear(0.1);
- camera.setFar(4096);
-
- let view = new renderEngine.View();
- camera.view = view;
camera.dirty = true;
- this._matrixDirty = true;
this._inited = false;
this._camera = camera;
}
@@ -107,7 +142,7 @@ let Camera = cc.Class({
editor: CC_EDITOR && {
menu: 'i18n:MAIN_MENU.component.others/Camera',
inspector: 'packages://inspector/inspectors/comps/camera.js',
- executeInEditMode: false
+ executeInEditMode: true
},
properties: {
@@ -117,12 +152,20 @@ let Camera = cc.Class({
_depth: 0,
_zoomRatio: 1,
_targetTexture: null,
+ _fov: 60,
+ _orthoSize: 10,
+ _nearClip: 1,
+ _farClip: 4096,
+ _ortho: true,
+ _rect: cc.rect(0, 0, 1, 1),
+ _renderStages: 1,
+ _alignWithScreen: true,
/**
* !#en
- * The camera zoom ratio.
+ * The camera zoom ratio, only support 2D camera.
* !#zh
- * 摄像机缩放比率
+ * 摄像机缩放比率, 只支持 2D camera。
* @property {Number} zoomRatio
*/
zoomRatio: {
@@ -131,8 +174,120 @@ let Camera = cc.Class({
},
set (value) {
this._zoomRatio = value;
- this._matrixDirty = true;
- }
+ },
+ tooltip: CC_DEV && 'i18n:COMPONENT.camera.zoomRatio',
+ },
+
+ /**
+ * !#en
+ * Field of view. The width of the Camera’s view angle, measured in degrees along the local Y axis.
+ * !#zh
+ * 决定摄像机视角的宽度,当摄像机处于透视投影模式下这个属性才会生效。
+ * @property {Number} fov
+ * @default 60
+ */
+ fov: {
+ get () {
+ return this._fov;
+ },
+ set (v) {
+ this._fov = v;
+ },
+ tooltip: CC_DEV && 'i18n:COMPONENT.camera.fov',
+ },
+
+ /**
+ * !#en
+ * The viewport size of the Camera when set to orthographic projection.
+ * !#zh
+ * 摄像机在正交投影模式下的视窗大小。
+ * @property {Number} orthoSize
+ * @default 10
+ */
+ orthoSize: {
+ get () {
+ return this._orthoSize;
+ },
+ set (v) {
+ this._orthoSize = v;
+ },
+ tooltip: CC_DEV && 'i18n:COMPONENT.camera.orthoSize',
+ },
+
+ /**
+ * !#en
+ * The near clipping plane.
+ * !#zh
+ * 摄像机的近剪裁面。
+ * @property {Number} nearClip
+ * @default 0.1
+ */
+ nearClip: {
+ get () {
+ return this._nearClip;
+ },
+ set (v) {
+ this._nearClip = v;
+ this._updateClippingpPlanes();
+ },
+ tooltip: CC_DEV && 'i18n:COMPONENT.camera.nearClip',
+ },
+
+ /**
+ * !#en
+ * The far clipping plane.
+ * !#zh
+ * 摄像机的远剪裁面。
+ * @property {Number} farClip
+ * @default 4096
+ */
+ farClip: {
+ get () {
+ return this._farClip;
+ },
+ set (v) {
+ this._farClip = v;
+ this._updateClippingpPlanes();
+ },
+ tooltip: CC_DEV && 'i18n:COMPONENT.camera.farClip',
+ },
+
+ /**
+ * !#en
+ * Is the camera orthographic (true) or perspective (false)?
+ * !#zh
+ * 设置摄像机的投影模式是正交还是透视模式。
+ * @property {Boolean} ortho
+ * @default false
+ */
+ ortho: {
+ get () {
+ return this._ortho;
+ },
+ set (v) {
+ this._ortho = v;
+ this._updateProjection();
+ },
+ tooltip: CC_DEV && 'i18n:COMPONENT.camera.ortho',
+ },
+
+ /**
+ * !#en
+ * Four values (0 ~ 1) that indicate where on the screen this camera view will be drawn.
+ * !#zh
+ * 决定摄像机绘制在屏幕上哪个位置,值为(0 ~ 1)。
+ * @property {Rect} rect
+ * @default cc.rect(0,0,1,1)
+ */
+ rect: {
+ get () {
+ return this._rect;
+ },
+ set (v) {
+ this._rect = v;
+ this._updateRect();
+ },
+ tooltip: CC_DEV && 'i18n:COMPONENT.camera.rect',
},
/**
@@ -149,7 +304,8 @@ let Camera = cc.Class({
set (value) {
this._cullingMask = value;
this._updateCameraMask();
- }
+ },
+ tooltip: CC_DEV && 'i18n:COMPONENT.camera.cullingMask',
},
/**
@@ -168,7 +324,8 @@ let Camera = cc.Class({
if (this._camera) {
this._camera.setClearFlags(value);
}
- }
+ },
+ tooltip: CC_DEV && 'i18n:COMPONENT.camera.clearFlags',
},
/**
@@ -183,16 +340,19 @@ let Camera = cc.Class({
return this._backgroundColor;
},
set (value) {
- this._backgroundColor = value;
- this._updateBackgroundColor();
- }
+ if (!this._backgroundColor.equals(value)) {
+ this._backgroundColor.set(value);
+ this._updateBackgroundColor();
+ }
+ },
+ tooltip: CC_DEV && 'i18n:COMPONENT.camera.backgroundColor',
},
/**
* !#en
- * Camera's depth in the camera rendering order.
+ * Camera's depth in the camera rendering order. Cameras with higher depth are rendered after cameras with lower depth.
* !#zh
- * 摄像机深度,用于决定摄像机的渲染顺序。
+ * 摄像机深度。用于决定摄像机的渲染顺序,值越大渲染在越上层。
* @property {Number} depth
*/
depth: {
@@ -200,11 +360,21 @@ let Camera = cc.Class({
return this._depth;
},
set (value) {
+ if (Camera.main === this) {
+ if (this._depth < value) {
+ updateMainCamera();
+ }
+ }
+ else if (Camera.main && value < Camera.main._depth && _cameras.includes(this)) {
+ Camera.main = this;
+ }
+
this._depth = value;
if (this._camera) {
- this._camera._sortDepth = value;
+ this._camera.setPriority(value);
}
- }
+ },
+ tooltip: CC_DEV && 'i18n:COMPONENT.camera.depth',
},
/**
@@ -223,6 +393,45 @@ let Camera = cc.Class({
set (value) {
this._targetTexture = value;
this._updateTargetTexture();
+ },
+ tooltip: CC_DEV && 'i18n:COMPONENT.camera.targetTexture',
+ },
+
+ /**
+ * !#en
+ * Sets the camera's render stages.
+ * !#zh
+ * 设置摄像机渲染的阶段
+ * @property {Number} renderStages
+ */
+ renderStages: {
+ get () {
+ return this._renderStages;
+ },
+ set (val) {
+ this._renderStages = val;
+ this._updateStages();
+ },
+ tooltip: CC_DEV && 'i18n:COMPONENT.camera.renderStages',
+ },
+
+ /**
+ * !#en Whether auto align camera viewport to screen
+ * !#zh 是否自动将摄像机的视口对准屏幕
+ * @property {Boolean} alignWithScreen
+ */
+ alignWithScreen: {
+ get () {
+ return this._alignWithScreen;
+ },
+ set (v) {
+ this._alignWithScreen = v;
+ }
+ },
+
+ _is3D: {
+ get () {
+ return this.node && this.node._is3DNode;
}
}
},
@@ -230,9 +439,9 @@ let Camera = cc.Class({
statics: {
/**
* !#en
- * The first enabled camera.
+ * The primary camera in the scene. Returns the rear most rendered camera, which is the camera with the lowest depth.
* !#zh
- * 第一个被激活的摄像机。
+ * 当前场景中激活的主摄像机。将会返回渲染在屏幕最底层,也就是 depth 最小的摄像机。
* @property {Camera} main
* @static
*/
@@ -242,7 +451,7 @@ let Camera = cc.Class({
* !#en
* All enabled cameras.
* !#zh
- * 激活的所有摄像机。
+ * 当前激活的所有摄像机。
* @property {[Camera]} cameras
* @static
*/
@@ -271,28 +480,36 @@ let Camera = cc.Class({
return null;
},
+ _findRendererCamera (node) {
+ let cameras = renderer.scene._cameras;
+ for (let i = 0; i < cameras._count; i++) {
+ if (cameras._data[i]._cullingMask & node._cullingMask) {
+ return cameras._data[i];
+ }
+ }
+ return null;
+ },
+
_setupDebugCamera () {
if (_debugCamera) return;
if (game.renderType === game.RENDER_TYPE_CANVAS) return;
- let camera = new renderEngine.Camera();
+ let camera = new RendererCamera();
_debugCamera = camera;
-
+
camera.setStages([
- 'transparent'
+ 'opaque',
]);
-
+
camera.setFov(Math.PI * 60 / 180);
camera.setNear(0.1);
camera.setFar(4096);
- let view = new renderEngine.View();
- camera.view = view;
camera.dirty = true;
- camera._cullingMask = camera.view._cullingMask = 1 << cc.Node.BuiltinGroupIndex.DEBUG;
- camera._sortDepth = cc.macro.MAX_ZINDEX;
+ camera.cullingMask = 1 << cc.Node.BuiltinGroupIndex.DEBUG;
+ camera.setPriority(cc.macro.MAX_ZINDEX);
camera.setClearFlags(0);
- camera.setColor(0,0,0,0);
+ camera.setColor(0, 0, 0, 0);
let node = new cc.Node();
camera.setNode(node);
@@ -307,168 +524,223 @@ let Camera = cc.Class({
_updateCameraMask () {
if (this._camera) {
let mask = this._cullingMask & (~(1 << cc.Node.BuiltinGroupIndex.DEBUG));
- this._camera._cullingMask = mask;
- this._camera.view._cullingMask = mask;
+ this._camera.cullingMask = mask;
}
},
_updateBackgroundColor () {
- if (this._camera) {
- let color = this._backgroundColor;
- this._camera.setColor(
- color.r / 255,
- color.g / 255,
- color.b / 255,
- color.a / 255,
- );
- }
+ if (!this._camera) return;
+
+ let color = this._backgroundColor;
+ this._camera.setColor(
+ color.r / 255,
+ color.g / 255,
+ color.b / 255,
+ color.a / 255,
+ );
},
_updateTargetTexture () {
+ if (!this._camera) return;
+
let texture = this._targetTexture;
- if (this._camera) {
- this._camera._framebuffer = texture ? texture._framebuffer : null;
- }
+ this._camera.setFrameBuffer(texture ? texture._framebuffer : null);
+ },
+
+ _updateClippingpPlanes () {
+ if (!this._camera) return;
+ this._camera.setNear(this._nearClip);
+ this._camera.setFar(this._farClip);
+ },
+
+ _updateProjection () {
+ if (!this._camera) return;
+ let type = this._ortho ? 1 : 0;
+ this._camera.setType(type);
},
- _onMatrixDirty () {
- this._matrixDirty = true;
+ _updateRect () {
+ if (!this._camera) return;
+ let rect = this._rect;
+ this._camera.setRect(rect.x, rect.y, rect.width, rect.height);
+ },
+
+ _updateStages () {
+ let flags = this._renderStages;
+ let stages = [];
+ if (flags & StageFlags.OPAQUE) {
+ stages.push('opaque');
+ }
+ if (flags & StageFlags.TRANSPARENT) {
+ stages.push('transparent');
+ }
+ this._camera.setStages(stages);
},
_init () {
if (this._inited) return;
this._inited = true;
- if (this._camera) {
- this._camera.setNode(this.node);
- this._camera.setClearFlags(this._clearFlags);
- this._camera._sortDepth = this._depth;
- this._updateBackgroundColor();
- this._updateCameraMask();
- this._updateTargetTexture();
- }
+ let camera = this._camera;
+ if (!camera) return;
+ camera.setNode(this.node);
+ camera.setClearFlags(this._clearFlags);
+ camera.setPriority(this._depth);
+ this._updateBackgroundColor();
+ this._updateCameraMask();
+ this._updateTargetTexture();
+ this._updateClippingpPlanes();
+ this._updateProjection();
+ this._updateStages();
+ this._updateRect();
+ this.beforeDraw();
},
- onLoad () {
+ __preload () {
this._init();
},
onEnable () {
- this._matrixDirty = true;
- if (game.renderType !== game.RENDER_TYPE_CANVAS) {
+ if (!CC_EDITOR && game.renderType !== game.RENDER_TYPE_CANVAS) {
cc.director.on(cc.Director.EVENT_BEFORE_DRAW, this.beforeDraw, this);
renderer.scene.addCamera(this._camera);
}
_cameras.push(this);
+ if (!Camera.main || (this._depth < Camera.main._depth)) {
+ Camera.main = this;
+ }
},
onDisable () {
- if (game.renderType !== game.RENDER_TYPE_CANVAS) {
+ if (!CC_EDITOR && game.renderType !== game.RENDER_TYPE_CANVAS) {
cc.director.off(cc.Director.EVENT_BEFORE_DRAW, this.beforeDraw, this);
renderer.scene.removeCamera(this._camera);
}
- cc.js.array.remove(_cameras, this);
+ cc.js.array.fastRemove(_cameras, this);
+ if (Camera.main === this) {
+ Camera.main = null;
+ updateMainCamera();
+ }
},
/**
* !#en
- * Returns the matrix that transform the node's (local) space coordinates into the camera's space coordinates.
+ * Get the screen to world matrix, only support 2D camera which alignWithScreen is true.
* !#zh
- * 返回一个将节点坐标系转换到摄像机坐标系下的矩阵
- * @method getNodeToCameraTransform
- * @param {Node} node - the node which should transform
- * @return {AffineTransform}
+ * 获取屏幕坐标系到世界坐标系的矩阵,只适用于 alignWithScreen 为 true 的 2D 摄像机。
+ * @method getScreenToWorldMatrix2D
+ * @param {Mat4} out - the matrix to receive the result
+ * @return {Mat4} out
*/
- getNodeToCameraTransform (node) {
- let out = AffineTrans.identity();
- node.getWorldMatrix(_mat4_temp_2);
- if (this.containsNode(node)) {
- this.getWorldToCameraMatrix(_mat4_temp_1);
- mat4.mul(_mat4_temp_2, _mat4_temp_2, _mat4_temp_1);
- }
- AffineTrans.fromMat4(out, _mat4_temp_2);
+ getScreenToWorldMatrix2D (out) {
+ this.getWorldToScreenMatrix2D(out);
+ Mat4.invert(out, out);
return out;
},
/**
* !#en
- * Conver a camera coordinates point to world coordinates.
+ * Get the world to camera matrix, only support 2D camera which alignWithScreen is true.
* !#zh
- * 将一个摄像机坐标系下的点转换到世界坐标系下。
- * @method getCameraToWorldPoint
- * @param {Vec2} point - the point which should transform
- * @param {Vec2} out - the point to receive the result
- * @return {Vec2}
+ * 获取世界坐标系到摄像机坐标系的矩阵,只适用于 alignWithScreen 为 true 的 2D 摄像机。
+ * @method getWorldToScreenMatrix2D
+ * @param {Mat4} out - the matrix to receive the result
+ * @return {Mat4} out
*/
- getCameraToWorldPoint (point, out) {
- out = out || cc.v2();
- this.getCameraToWorldMatrix(_mat4_temp_1);
- vec2.transformMat4(out, point, _mat4_temp_1);
+ getWorldToScreenMatrix2D (out) {
+ this.node.getWorldRT(_mat4_temp_1);
+
+ let zoomRatio = this.zoomRatio;
+ let _mat4_temp_1m = _mat4_temp_1.m;
+ _mat4_temp_1m[0] *= zoomRatio;
+ _mat4_temp_1m[1] *= zoomRatio;
+ _mat4_temp_1m[4] *= zoomRatio;
+ _mat4_temp_1m[5] *= zoomRatio;
+
+ let m12 = _mat4_temp_1m[12];
+ let m13 = _mat4_temp_1m[13];
+
+ let center = cc.visibleRect.center;
+ _mat4_temp_1m[12] = center.x - (_mat4_temp_1m[0] * m12 + _mat4_temp_1m[4] * m13);
+ _mat4_temp_1m[13] = center.y - (_mat4_temp_1m[1] * m12 + _mat4_temp_1m[5] * m13);
+
+ if (out !== _mat4_temp_1) {
+ Mat4.copy(out, _mat4_temp_1);
+ }
return out;
},
/**
* !#en
- * Conver a world coordinates point to camera coordinates.
+ * Convert point from screen to world.
* !#zh
- * 将一个世界坐标系下的点转换到摄像机坐标系下。
- * @method getWorldToCameraPoint
- * @param {Vec2} point
- * @param {Vec2} out - the point to receive the result
- * @return {Vec2}
+ * 将坐标从屏幕坐标系转换到世界坐标系。
+ * @method getScreenToWorldPoint
+ * @param {Vec3|Vec2} screenPosition
+ * @param {Vec3|Vec2} [out]
+ * @return {Vec3|Vec2} out
*/
- getWorldToCameraPoint (point, out) {
- out = out || cc.v2();
- this.getWorldToCameraMatrix(_mat4_temp_1);
- vec2.transformMat4(out, point, _mat4_temp_1);
+ getScreenToWorldPoint (screenPosition, out) {
+ if (this.node.is3DNode) {
+ out = out || new cc.Vec3();
+ this._camera.screenToWorld(out, screenPosition, cc.visibleRect.width, cc.visibleRect.height);
+ }
+ else {
+ out = out || new cc.Vec2();
+ this.getScreenToWorldMatrix2D(_mat4_temp_1);
+ Vec2.transformMat4(out, screenPosition, _mat4_temp_1);
+ }
return out;
},
/**
* !#en
- * Get the camera to world matrix
+ * Convert point from world to screen.
* !#zh
- * 获取摄像机坐标系到世界坐标系的矩阵
- * @method getCameraToWorldMatrix
- * @param {Mat4} out - the matrix to receive the result
- * @return {Mat4}
+ * 将坐标从世界坐标系转化到屏幕坐标系。
+ * @method getWorldToScreenPoint
+ * @param {Vec3|Vec2} worldPosition
+ * @param {Vec3|Vec2} [out]
+ * @return {Vec3|Vec2} out
*/
- getCameraToWorldMatrix (out) {
- this.getWorldToCameraMatrix(out);
- mat4.invert(out, out);
+ getWorldToScreenPoint (worldPosition, out) {
+ if (this.node.is3DNode) {
+ out = out || new cc.Vec3();
+ this._camera.worldToScreen(out, worldPosition, cc.visibleRect.width, cc.visibleRect.height);
+ }
+ else {
+ out = out || new cc.Vec2();
+ this.getWorldToScreenMatrix2D(_mat4_temp_1);
+ Vec2.transformMat4(out, worldPosition, _mat4_temp_1);
+ }
+
return out;
},
-
/**
* !#en
- * Get the world to camera matrix
+ * Get a ray from screen position
* !#zh
- * 获取世界坐标系到摄像机坐标系的矩阵
- * @method getWorldToCameraMatrix
- * @param {Mat4} out - the matrix to receive the result
- * @return {Mat4}
+ * 从屏幕坐标获取一条射线
+ * @method getRay
+ * @param {Vec2} screenPos
+ * @return {Ray}
*/
- getWorldToCameraMatrix (out) {
- this.node.getWorldRT(_mat4_temp_1);
-
- let zoomRatio = this.zoomRatio;
- _mat4_temp_1.m00 *= zoomRatio;
- _mat4_temp_1.m01 *= zoomRatio;
- _mat4_temp_1.m04 *= zoomRatio;
- _mat4_temp_1.m05 *= zoomRatio;
-
- let m12 = _mat4_temp_1.m12;
- let m13 = _mat4_temp_1.m13;
-
- let center = cc.visibleRect.center;
- _mat4_temp_1.m12 = center.x - (_mat4_temp_1.m00 * m12 + _mat4_temp_1.m04 * m13);
- _mat4_temp_1.m13 = center.y - (_mat4_temp_1.m01 * m12 + _mat4_temp_1.m05 * m13);
+ getRay (screenPos) {
+ if (!cc.geomUtils) return screenPos;
+
+ Vec3.set(_v3_temp_3, screenPos.x, screenPos.y, 1);
+ this._camera.screenToWorld(_v3_temp_2, _v3_temp_3, cc.visibleRect.width, cc.visibleRect.height);
- if (out !== _mat4_temp_1) {
- mat4.copy(out, _mat4_temp_1);
+ if (this.ortho) {
+ Vec3.set(_v3_temp_3, screenPos.x, screenPos.y, -1);
+ this._camera.screenToWorld(_v3_temp_1, _v3_temp_3, cc.visibleRect.width, cc.visibleRect.height);
}
- return out;
+ else {
+ this.node.getWorldPosition(_v3_temp_1);
+ }
+
+ return Ray.fromPoints(new Ray(), _v3_temp_1, _v3_temp_2);
},
/**
@@ -481,7 +753,7 @@ let Camera = cc.Class({
* @return {Boolean}
*/
containsNode (node) {
- return node._cullingMask & this.cullingMask;
+ return (node._cullingMask & this.cullingMask) > 0;
},
/**
@@ -490,47 +762,140 @@ let Camera = cc.Class({
* !#zh
* 手动渲染摄像机。
* @method render
- * @param {Node} root
+ * @param {Node} [rootNode]
*/
- render (root) {
- root = root || cc.director.getScene();
- if (!root) return null;
+ render (rootNode) {
+ rootNode = rootNode || cc.director.getScene();
+ if (!rootNode) return null;
// force update node world matrix
this.node.getWorldMatrix(_mat4_temp_1);
this.beforeDraw();
- renderer._walker.visit(root);
- renderer._forward.renderCamera(this._camera, renderer.scene);
- },
-
- beforeDraw: function () {
- let node = this.node;
-
- if (!this._matrixDirty && !node._worldMatDirty)
- return;
- let camera = this._camera;
- let fov = Math.atan(Math.tan(this._fov/2) / this.zoomRatio)*2;
- camera.setFov(fov);
+ RenderFlow.renderCamera(this._camera, rootNode);
+ },
+ _onAlignWithScreen () {
let height = cc.game.canvas.height / cc.view._scaleY;
let targetTexture = this._targetTexture;
if (targetTexture) {
- height = targetTexture.height;
+ if (CC_EDITOR) {
+ height = cc.engine.getDesignResolutionSize().height;
+ }
+ else {
+ height = cc.visibleRect.height;
+ }
}
- node._updateWorldMatrix();
- _vec3_temp_1.x = node._worldMatrix.m12;
- _vec3_temp_1.y = node._worldMatrix.m13;
- _vec3_temp_1.z = 0;
+ let fov = this._fov * cc.macro.RAD;
+ this.node.z = height / (Math.tan(fov / 2) * 2);
+
+ fov = Math.atan(Math.tan(fov / 2) / this.zoomRatio) * 2;
+ this._camera.setFov(fov);
+ this._camera.setOrthoHeight(height / 2 / this.zoomRatio);
+ this.node.setRotation(0, 0, 0, 1);
+ },
- node.z = height / 1.1566;
- node.lookAt(_vec3_temp_1);
+ beforeDraw () {
+ if (!this._camera) return;
- this._matrixDirty = false;
- camera.dirty = true;
+ if (this._alignWithScreen) {
+ this._onAlignWithScreen();
+ }
+ else {
+ let fov = this._fov * cc.macro.RAD;
+ fov = Math.atan(Math.tan(fov / 2) / this.zoomRatio) * 2;
+ this._camera.setFov(fov);
+
+ this._camera.setOrthoHeight(this._orthoSize / this.zoomRatio);
+ }
+
+ this._camera.dirty = true;
}
});
+// deprecated
+cc.js.mixin(Camera.prototype, {
+ /**
+ * !#en
+ * Returns the matrix that transform the node's (local) space coordinates into the camera's space coordinates.
+ * !#zh
+ * 返回一个将节点坐标系转换到摄像机坐标系下的矩阵
+ * @method getNodeToCameraTransform
+ * @deprecated since v2.0.0
+ * @param {Node} node - the node which should transform
+ * @return {AffineTransform}
+ */
+ getNodeToCameraTransform (node) {
+ let out = AffineTrans.identity();
+ node.getWorldMatrix(_mat4_temp_2);
+ if (this.containsNode(node)) {
+ this.getWorldToCameraMatrix(_mat4_temp_1);
+ Mat4.mul(_mat4_temp_2, _mat4_temp_2, _mat4_temp_1);
+ }
+ AffineTrans.fromMat4(out, _mat4_temp_2);
+ return out;
+ },
+
+ /**
+ * !#en
+ * Conver a camera coordinates point to world coordinates.
+ * !#zh
+ * 将一个摄像机坐标系下的点转换到世界坐标系下。
+ * @method getCameraToWorldPoint
+ * @deprecated since v2.1.3
+ * @param {Vec2} point - the point which should transform
+ * @param {Vec2} [out] - the point to receive the result
+ * @return {Vec2} out
+ */
+ getCameraToWorldPoint (point, out) {
+ return this.getScreenToWorldPoint(point, out);
+ },
+
+ /**
+ * !#en
+ * Conver a world coordinates point to camera coordinates.
+ * !#zh
+ * 将一个世界坐标系下的点转换到摄像机坐标系下。
+ * @method getWorldToCameraPoint
+ * @deprecated since v2.1.3
+ * @param {Vec2} point
+ * @param {Vec2} [out] - the point to receive the result
+ * @return {Vec2} out
+ */
+ getWorldToCameraPoint (point, out) {
+ return this.getWorldToScreenPoint(point, out);
+ },
+
+ /**
+ * !#en
+ * Get the camera to world matrix
+ * !#zh
+ * 获取摄像机坐标系到世界坐标系的矩阵
+ * @method getCameraToWorldMatrix
+ * @deprecated since v2.1.3
+ * @param {Mat4} out - the matrix to receive the result
+ * @return {Mat4} out
+ */
+ getCameraToWorldMatrix (out) {
+ return this.getScreenToWorldMatrix2D(out);
+ },
+
+
+ /**
+ * !#en
+ * Get the world to camera matrix
+ * !#zh
+ * 获取世界坐标系到摄像机坐标系的矩阵
+ * @method getWorldToCameraMatrix
+ * @deprecated since v2.1.3
+ * @param {Mat4} out - the matrix to receive the result
+ * @return {Mat4} out
+ */
+ getWorldToCameraMatrix (out) {
+ return this.getWorldToScreenMatrix2D(out);
+ },
+});
+
module.exports = cc.Camera = Camera;
diff --git a/cocos2d/core/collider/CCBoxCollider.js b/cocos2d/core/collider/CCBoxCollider.js
index 25a32652112..3f9569fb77b 100644
--- a/cocos2d/core/collider/CCBoxCollider.js
+++ b/cocos2d/core/collider/CCBoxCollider.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -71,12 +71,14 @@ cc.Collider.Box = cc.Class({
}
},
- resetInEditor: CC_EDITOR && function () {
- var size = this.node.getContentSize();
- if (size.width !== 0 && size.height !== 0) {
- this.size = cc.size( size );
- this.offset.x = (0.5 - this.node.anchorX) * size.width;
- this.offset.y = (0.5 - this.node.anchorY) * size.height;
+ resetInEditor: CC_EDITOR && function (didResetToDefault) {
+ if (didResetToDefault) {
+ var size = this.node.getContentSize();
+ if (size.width !== 0 && size.height !== 0) {
+ this.size = cc.size( size );
+ this.offset.x = (0.5 - this.node.anchorX) * size.width;
+ this.offset.y = (0.5 - this.node.anchorY) * size.height;
+ }
}
}
});
@@ -88,6 +90,13 @@ cc.Collider.Box = cc.Class({
* @extends Collider
* @uses Collider.Box
*/
+/**
+ * !#en
+ * Collider info in world coordinate.
+ * !#zh
+ * 碰撞体的世界坐标系下的信息。
+ * @property {ColliderInfo} world
+ */
var BoxCollider = cc.Class({
name: 'cc.BoxCollider',
extends: cc.Collider,
diff --git a/cocos2d/core/collider/CCCircleCollider.js b/cocos2d/core/collider/CCCircleCollider.js
index 54006a0c4a1..fcb841805f2 100644
--- a/cocos2d/core/collider/CCCircleCollider.js
+++ b/cocos2d/core/collider/CCCircleCollider.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -41,6 +41,7 @@ cc.Collider.Circle = cc.Class({
* @type {Vec2}
*/
offset: {
+ tooltip: CC_DEV && 'i18n:COMPONENT.physics.physics_collider.offset',
get: function () {
return this._offset;
},
@@ -67,11 +68,13 @@ cc.Collider.Circle = cc.Class({
}
},
- resetInEditor: CC_EDITOR && function () {
- var size = this.node.getContentSize();
- var radius = Math.max(size.width, size.height);
- if (radius !== 0) {
- this.radius = radius;
+ resetInEditor: CC_EDITOR && function (didResetToDefault) {
+ if (didResetToDefault) {
+ var size = this.node.getContentSize();
+ var radius = Math.max(size.width, size.height);
+ if (radius !== 0) {
+ this.radius = radius;
+ }
}
}
});
@@ -83,6 +86,13 @@ cc.Collider.Circle = cc.Class({
* @extends Collider
* @uses Collider.Circle
*/
+/**
+ * !#en
+ * Collider info in world coordinate.
+ * !#zh
+ * 碰撞体的世界坐标系下的信息。
+ * @property {ColliderInfo} world
+ */
var CircleCollider = cc.Class({
name: 'cc.CircleCollider',
extends: cc.Collider,
diff --git a/cocos2d/core/collider/CCCollider.js b/cocos2d/core/collider/CCCollider.js
index af9eb39ac95..4e28d92427c 100644
--- a/cocos2d/core/collider/CCCollider.js
+++ b/cocos2d/core/collider/CCCollider.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/collider/CCCollisionManager.js b/cocos2d/core/collider/CCCollisionManager.js
index 07f9c5ca1d7..11ae4f43c10 100644
--- a/cocos2d/core/collider/CCCollisionManager.js
+++ b/cocos2d/core/collider/CCCollisionManager.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -23,29 +23,30 @@
THE SOFTWARE.
****************************************************************************/
+import Vec2 from '../value-types/vec2';
+
const Contact = require('./CCContact');
const CollisionType = Contact.CollisionType;
const NodeEvent = require('../CCNode').EventType;
-const math = cc.vmath;
-
-let _vec2 = cc.v2();
+let _vec2 = new Vec2();
function obbApplyMatrix (rect, mat4, out_bl, out_tl, out_tr, out_br) {
- var x = rect.x;
- var y = rect.y;
- var width = rect.width;
- var height = rect.height;
-
- var m00 = mat4.m00, m01 = mat4.m01, m04 = mat4.m04, m05 = mat4.m05;
- var m12 = mat4.m12, m13 = mat4.m13;
-
- var tx = m00 * x + m04 * y + m12;
- var ty = m01 * x + m05 * y + m13;
- var xa = m00 * width;
- var xb = m01 * width;
- var yc = m04 * height;
- var yd = m05 * height;
+ let x = rect.x;
+ let y = rect.y;
+ let width = rect.width;
+ let height = rect.height;
+
+ let mat4m = mat4.m;
+ let m00 = mat4m[0], m01 = mat4m[1], m04 = mat4m[4], m05 = mat4m[5];
+ let m12 = mat4m[12], m13 = mat4m[13];
+
+ let tx = m00 * x + m04 * y + m12;
+ let ty = m01 * x + m05 * y + m13;
+ let xa = m00 * width;
+ let xb = m01 * width;
+ let yc = m04 * height;
+ let yd = m05 * height;
out_tl.x = tx;
out_tl.y = ty;
@@ -55,7 +56,59 @@ function obbApplyMatrix (rect, mat4, out_bl, out_tl, out_tr, out_br) {
out_bl.y = yd + ty;
out_br.x = xa + yc + tx;
out_br.y = xb + yd + ty;
-};
+}
+
+/**
+ * !#en
+ * Collider Info.
+ * !#zh
+ * 碰撞体信息。
+ * @class ColliderInfo
+ */
+/**
+ * !#en
+ * Collider aabb information of last frame
+ * !#zh
+ * 碰撞体上一帧的 aabb 信息
+ * @property {Rect} preAabb
+ */
+/**
+ * !#en
+ * Collider aabb information of current frame
+ * !#zh
+ * 碰撞体当前帧的 aabb 信息
+ * @property {Rect} aabb
+ */
+/**
+ * !#en
+ * Collider matrix
+ * !#zh
+ * 碰撞体的矩阵信息
+ * @property {Mat4} matrix
+ */
+/**
+ * !#en
+ * Collider radius (for CircleCollider)
+ * !#zh
+ * 碰撞体的半径(只对 CircleCollider 有效)
+ * @property {Number} radius
+ */
+/**
+ * !#en
+ * Collider position (for CircleCollider)
+ * !#zh
+ * 碰撞体的位置(只对 CircleCollider 有效)
+ * @property {Vec2} position
+ */
+/**
+* !#en
+ * Collider points (for BoxCollider and PolygonCollider)
+ * !#zh
+ * 碰撞体的顶点信息(只对 BoxCollider 和 PolygonCollider 有效)
+ * @property {Vec2[]} points
+ */
+
+
/**
* !#en
@@ -224,7 +277,7 @@ let CollisionManager = cc.Class({
let world = collider.world = {};
world.aabb = cc.rect();
world.preAabb = cc.rect();
- world.matrix = math.mat4.create();
+ world.matrix = cc.mat4();
world.radius = 0;
@@ -284,19 +337,20 @@ let CollisionManager = cc.Class({
}
else if (collider instanceof cc.CircleCollider) {
// calculate world position
- math.vec2.transformMat4(_vec2, collider.offset, m);
+ Vec2.transformMat4(_vec2, collider.offset, m);
world.position.x = _vec2.x;
world.position.y = _vec2.y;
// calculate world radius
- let tempx = m.m12, tempy = m.m13;
- m.m12 = m.m13 = 0;
+ let mm = m.m;
+ let tempx = mm[12], tempy = mm[13];
+ mm[12] = mm[13] = 0;
_vec2.x = collider.radius;
_vec2.y = 0;
- math.vec2.transformMat4(_vec2, _vec2, m);
+ Vec2.transformMat4(_vec2, _vec2, m);
let d = Math.sqrt(_vec2.x * _vec2.x + _vec2.y * _vec2.y);
world.radius = d;
@@ -306,8 +360,8 @@ let CollisionManager = cc.Class({
aabb.width = d * 2;
aabb.height = d * 2;
- m.m12 = tempx;
- m.m13 = tempy;
+ mm[12] = tempx;
+ mm[13] = tempy;
}
else if (collider instanceof cc.PolygonCollider) {
let points = collider.points;
@@ -324,7 +378,7 @@ let CollisionManager = cc.Class({
_vec2.x = points[i].x + offset.x;
_vec2.y = points[i].y + offset.y;
- math.vec2.transformMat4(_vec2, _vec2, m);
+ Vec2.transformMat4(_vec2, _vec2, m);
let x = _vec2.x;
let y = _vec2.y;
@@ -393,8 +447,12 @@ let CollisionManager = cc.Class({
let colliders = node.getComponents(cc.Collider);
for (let i = 0, l = colliders.length; i < l; i++) {
- this.removeCollider(colliders[i]);
- this.addCollider(colliders[i]);
+ let collider = colliders[i];
+ if(cc.PhysicsCollider && collider instanceof cc.PhysicsCollider) {
+ continue;
+ }
+ this.removeCollider(collider);
+ this.addCollider(collider);
}
},
diff --git a/cocos2d/core/collider/CCContact.js b/cocos2d/core/collider/CCContact.js
index d9751718362..923a620932c 100644
--- a/cocos2d/core/collider/CCContact.js
+++ b/cocos2d/core/collider/CCContact.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/collider/CCIntersection.js b/cocos2d/core/collider/CCIntersection.js
index 600077025ac..d34282a3558 100644
--- a/cocos2d/core/collider/CCIntersection.js
+++ b/cocos2d/core/collider/CCIntersection.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -324,7 +324,7 @@ Intersection.pointInPolygon = pointInPolygon;
* @param {Vec2} start - The start point of line
* @param {Vec2} end - The end point of line
* @param {boolean} isSegment - whether this line is a segment
- * @return {boolean}
+ * @return {number}
*/
function pointLineDistance(point, start, end, isSegment) {
var dx = end.x - start.x;
diff --git a/cocos2d/core/collider/CCPolygonCollider.js b/cocos2d/core/collider/CCPolygonCollider.js
index f1f8fc3a833..9e307e8d38e 100644
--- a/cocos2d/core/collider/CCPolygonCollider.js
+++ b/cocos2d/core/collider/CCPolygonCollider.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -84,6 +84,13 @@ cc.Collider.Polygon = cc.Class({
* @extends Collider
* @uses Collider.Polygon
*/
+/**
+ * !#en
+ * Collider info in world coordinate.
+ * !#zh
+ * 碰撞体的世界坐标系下的信息。
+ * @property {ColliderInfo} world
+ */
var PolygonCollider = cc.Class({
name: 'cc.PolygonCollider',
extends: cc.Collider,
diff --git a/cocos2d/core/collider/index.js b/cocos2d/core/collider/index.js
index 98873d2ee92..c1d23405673 100644
--- a/cocos2d/core/collider/index.js
+++ b/cocos2d/core/collider/index.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/component-scheduler.js b/cocos2d/core/component-scheduler.js
index e1d2bce0a81..d2faabccf96 100644
--- a/cocos2d/core/component-scheduler.js
+++ b/cocos2d/core/component-scheduler.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -34,22 +34,8 @@ var IsEditorOnEnableCalled = Flags.IsEditorOnEnableCalled;
var callerFunctor = CC_EDITOR && require('./utils/misc').tryCatchFunctor_EDITOR;
var callOnEnableInTryCatch = CC_EDITOR && callerFunctor('onEnable');
-var callStartInTryCatch = CC_EDITOR && callerFunctor('start', null, 'target._objFlags |= ' + IsStartCalled);
-var callUpdateInTryCatch = CC_EDITOR && callerFunctor('update', 'dt');
-var callLateUpdateInTryCatch = CC_EDITOR && callerFunctor('lateUpdate', 'dt');
var callOnDisableInTryCatch = CC_EDITOR && callerFunctor('onDisable');
-var callStart = CC_SUPPORT_JIT ? 'c.start();c._objFlags|=' + IsStartCalled : function (c) {
- c.start();
- c._objFlags |= IsStartCalled;
-};
-var callUpdate = CC_SUPPORT_JIT ? 'c.update(dt)' : function (c, dt) {
- c.update(dt);
-};
-var callLateUpdate = CC_SUPPORT_JIT ? 'c.lateUpdate(dt)' : function (c, dt) {
- c.lateUpdate(dt);
-};
-
function sortedIndex (array, comp) {
var order = comp.constructor._executionOrder;
var id = comp._id;
@@ -215,64 +201,107 @@ function enableInEditor (comp) {
}
}
-function createInvokeImpl (funcOrCode, useDt) {
- if (typeof funcOrCode === 'function') {
- if (useDt) {
- return function (iterator, dt) {
- var array = iterator.array;
- for (iterator.i = 0; iterator.i < array.length; ++iterator.i) {
- var comp = array[iterator.i];
- funcOrCode(comp, dt);
- }
- };
- }
- else {
- return function (iterator) {
- var array = iterator.array;
- for (iterator.i = 0; iterator.i < array.length; ++iterator.i) {
- var comp = array[iterator.i];
- funcOrCode(comp);
- }
- };
- }
- }
- else {
+// return function to simply call each component with try catch protection
+function createInvokeImpl (indiePath, useDt, ensureFlag, fastPath) {
+ if (CC_SUPPORT_JIT) {
// function (it) {
// var a = it.array;
// for (it.i = 0; it.i < a.length; ++it.i) {
- // var comp = a[it.i];
+ // var c = a[it.i];
// // ...
// }
// }
- var body = 'var a=it.array;' +
+ let body = 'var a=it.array;' +
'for(it.i=0;it.i= 0) {
- jsArray.fastRemoveAt(this.scheduleInNextFrame, index);
+ jsArray.fastRemoveAt(this._deferredComps, index);
return;
}
@@ -415,36 +444,44 @@ var ComponentScheduler = cc.Class({
},
_scheduleImmediate (comp) {
- if (comp.start && !(comp._objFlags & IsStartCalled)) {
+ if (typeof comp.start === 'function' && !(comp._objFlags & IsStartCalled)) {
this.startInvoker.add(comp);
}
- if (comp.update) {
+ if (typeof comp.update === 'function') {
this.updateInvoker.add(comp);
}
- if (comp.lateUpdate) {
+ if (typeof comp.lateUpdate === 'function') {
this.lateUpdateInvoker.add(comp);
}
},
_deferredSchedule () {
- var comps = this.scheduleInNextFrame;
+ var comps = this._deferredComps;
for (var i = 0, len = comps.length; i < len; i++) {
- var comp = comps[i];
- this._scheduleImmediate(comp);
+ this._scheduleImmediate(comps[i]);
}
comps.length = 0;
},
+ // Call new registered start schedule immediately since last time start phase calling in this frame
+ // See cocos-creator/2d-tasks/issues/256
+ _startForNewComps () {
+ if (this._deferredComps.length > 0) {
+ this._deferredSchedule();
+ this.startInvoker.invoke();
+ }
+ },
+
startPhase () {
// Start of this frame
this._updating = true;
- if (this.scheduleInNextFrame.length > 0) {
- this._deferredSchedule();
- }
-
// call start
this.startInvoker.invoke();
+
+ // Start components of new activated nodes during start
+ this._startForNewComps();
+
// if (CC_PREVIEW) {
// try {
// this.startInvoker.invoke();
@@ -471,7 +508,12 @@ var ComponentScheduler = cc.Class({
// End of this frame
this._updating = false;
- }
+
+ // Start components of new activated nodes during update and lateUpdate
+ // The start callback will be invoked immediately,
+ // update and lateUpdate callback will be running in the next frame
+ this._startForNewComps();
+ },
});
module.exports = ComponentScheduler;
diff --git a/cocos2d/core/components/CCAnimation.js b/cocos2d/core/components/CCAnimation.js
index d110f4e85e4..1d44a78771e 100644
--- a/cocos2d/core/components/CCAnimation.js
+++ b/cocos2d/core/components/CCAnimation.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -29,13 +29,11 @@ const AnimationClip = require('../../animation/animation-clip');
const EventTarget = require('../event/event-target');
const js = require('../platform/js');
-function equalClips (clip1, clip2) {
- if (clip1 === clip2) {
- return true;
- }
-
- return clip1 && clip2 && (clip1.name === clip2.name || clip1._uuid === clip2._uuid);
-}
+let equalClips = CC_EDITOR ? function (clip1, clip2) {
+ return clip1 === clip2 || (clip1 && clip2 && (clip1.name === clip2.name || clip1._uuid === clip2._uuid));
+} : function (clip1, clip2) {
+ return clip1 === clip2;
+};
/**
* !#en The event type supported by Animation
@@ -44,7 +42,7 @@ function equalClips (clip1, clip2) {
* @static
* @namespace Animationd
*/
-var EventType = cc.Enum({
+let EventType = cc.Enum({
/**
* !#en Emit when begin playing animation
* !#zh 开始播放时触发
@@ -87,7 +85,7 @@ var EventType = cc.Enum({
* @static
*/
FINISHED: 'finished'
-})
+});
/**
* !#en The animation component is used to play back animations.
@@ -114,7 +112,7 @@ var EventType = cc.Enum({
* @extends Component
* @uses EventTarget
*/
-var Animation = cc.Class({
+let Animation = cc.Class({
name: 'cc.Animation',
extends: require('./CCComponent'),
mixins: [EventTarget],
@@ -164,21 +162,13 @@ var Animation = cc.Class({
return;
}
- this._defaultClip = value;
-
- if (!value) {
- return;
+ if (this._defaultClip) {
+ this.removeClip(this._defaultClip, true);
}
-
- var clips = this._clips;
-
- for (var i = 0, l = clips.length; i < l; i++) {
- if (equalClips(value, clips[i])) {
- return;
- }
+ if (value) {
+ this.addClip(value);
}
-
- this.addClip(value);
+ this._defaultClip = value;
},
tooltip: CC_DEV && 'i18n:COMPONENT.animation.default_clip'
},
@@ -200,6 +190,20 @@ var Animation = cc.Class({
visible: false
},
+ // This property is used to watch clip changes in editor.
+ // Don't use in your game, use addClip/removeClip instead.
+ _writableClips: {
+ get () {
+ return this._clips;
+ },
+ set (val) {
+ this._didInit = false;
+ this._clips = val;
+ this._init();
+ },
+ type: [AnimationClip],
+ },
+
/**
* !#en All the clips used in this animation.
* !#zh 通过脚本可以访问并播放的 AnimationClip 列表。
@@ -229,9 +233,9 @@ var Animation = cc.Class({
start: function () {
if (!CC_EDITOR && this.playOnLoad && this._defaultClip) {
- var isPlaying = this._animator && this._animator.isPlaying;
+ let isPlaying = this._animator && this._animator.isPlaying;
if (!isPlaying) {
- var state = this.getAnimationState(this._defaultClip.name);
+ let state = this.getAnimationState(this._defaultClip.name);
this._animator.playState(state);
}
}
@@ -279,7 +283,7 @@ var Animation = cc.Class({
* animCtrl.play("linear");
*/
play: function (name, startTime) {
- var state = this.playAdditive(name, startTime);
+ let state = this.playAdditive(name, startTime);
this._animator.stopStatesExcept(state);
return state;
},
@@ -301,12 +305,12 @@ var Animation = cc.Class({
*/
playAdditive: function (name, startTime) {
this._init();
- var state = this.getAnimationState(name || (this._defaultClip && this._defaultClip.name));
+ let state = this.getAnimationState(name || (this._defaultClip && this._defaultClip.name));
if (state) {
this.enabled = true;
-
- var animator = this._animator;
+
+ let animator = this._animator;
if (animator.isPlaying && state.isPlaying) {
if (state.isPaused) {
animator.resumeState(state);
@@ -345,7 +349,7 @@ var Animation = cc.Class({
return;
}
if (name) {
- var state = this._nameToState[name];
+ let state = this._nameToState[name];
if (state) {
this._animator.stopState(state);
}
@@ -366,7 +370,7 @@ var Animation = cc.Class({
return;
}
if (name) {
- var state = this._nameToState[name];
+ let state = this._nameToState[name];
if (state) {
this._animator.pauseState(state);
}
@@ -387,7 +391,7 @@ var Animation = cc.Class({
return;
}
if (name) {
- var state = this._nameToState[name];
+ let state = this._nameToState[name];
if (state) {
this._animator.resumeState(state);
}
@@ -407,7 +411,7 @@ var Animation = cc.Class({
setCurrentTime: function (time, name) {
this._init();
if (name) {
- var state = this._nameToState[name];
+ let state = this._nameToState[name];
if (state) {
this._animator.setStateTime(state, time);
}
@@ -426,13 +430,13 @@ var Animation = cc.Class({
*/
getAnimationState: function (name) {
this._init();
- var state = this._nameToState[name];
+ let state = this._nameToState[name];
if (CC_EDITOR && (!state || !cc.js.array.contains(this._clips, state.clip))) {
this._didInit = false;
- if (this.animator) {
- this.animator.stop();
+ if (this._animator) {
+ this._animator.stop();
}
this._init();
@@ -468,7 +472,7 @@ var Animation = cc.Class({
// replace same name clip
newName = newName || clip.name;
- var oldState = this._nameToState[newName];
+ let oldState = this._nameToState[newName];
if (oldState) {
if (oldState.clip === clip) {
return oldState;
@@ -482,7 +486,7 @@ var Animation = cc.Class({
}
// replace state
- var newState = new cc.AnimationState(clip, newName);
+ let newState = new cc.AnimationState(clip, newName);
this._nameToState[newName] = newState;
return newState;
},
@@ -507,11 +511,10 @@ var Animation = cc.Class({
}
this._init();
- var state;
- for (var name in this._nameToState) {
+ let state;
+ for (let name in this._nameToState) {
state = this._nameToState[name];
- var stateClip = state.clip;
- if (stateClip === clip) {
+ if (equalClips(state.clip, clip)) {
break;
}
}
@@ -533,7 +536,7 @@ var Animation = cc.Class({
}
this._clips = this._clips.filter(function (item) {
- return item !== clip;
+ return !equalClips(item, clip);
});
if (state) {
@@ -553,7 +556,7 @@ var Animation = cc.Class({
this._init();
if (name) {
- var state = this._nameToState[name];
+ let state = this._nameToState[name];
if (state) {
state.sample();
}
@@ -588,6 +591,7 @@ var Animation = cc.Class({
* @typescript
* on(type: string, callback: (event: Event.EventCustom) => void, target?: any, useCapture?: boolean): (event: Event.EventCustom) => void
* on(type: string, callback: (event: T) => void, target?: any, useCapture?: boolean): (event: T) => void
+ * on(type: string, callback: (type: string, state: cc.AnimationState) => void, target?: any, useCapture?: boolean): (type: string, state: cc.AnimationState) => void
* @example
* onPlay: function (type, state) {
* // callback
@@ -599,11 +603,13 @@ var Animation = cc.Class({
on: function (type, callback, target, useCapture) {
this._init();
- var ret = this._EventTargetOn(type, callback, target, useCapture);
-
- var array = this._animator._anims.array;
- for (var i = 0; i < array.length; ++i) {
- array[i]._setListeners(this);
+ let ret = this._EventTargetOn(type, callback, target, useCapture);
+
+ if (type === 'lastframe') {
+ let states = this._nameToState;
+ for (let name in states) {
+ states[name]._lastframeEventOn = true;
+ }
}
return ret;
@@ -631,13 +637,14 @@ var Animation = cc.Class({
off: function (type, callback, target, useCapture) {
this._init();
- this._EventTargetOff(type, callback, target, useCapture);
-
- var nameToState = this._nameToState;
- for (var name in nameToState) {
- var state = nameToState[name];
- state._setListeners(null);
+ if (type === 'lastframe') {
+ let states = this._nameToState;
+ for (let name in states) {
+ states[name]._lastframeEventOn = false;
+ }
}
+
+ this._EventTargetOff(type, callback, target, useCapture);
},
///////////////////////////////////////////////////////////////////////////////
@@ -660,10 +667,10 @@ var Animation = cc.Class({
this._nameToState = js.createMap(true);
// create animation states
- var state = null;
- var defaultClipState = false;
- for (var i = 0; i < this._clips.length; ++i) {
- var clip = this._clips[i];
+ let state = null;
+ let defaultClipState = false;
+ for (let i = 0; i < this._clips.length; ++i) {
+ let clip = this._clips[i];
if (clip) {
state = new cc.AnimationState(clip);
diff --git a/cocos2d/core/components/CCAudioSource.js b/cocos2d/core/components/CCAudioSource.js
index ff525592d95..0b16bb53f00 100644
--- a/cocos2d/core/components/CCAudioSource.js
+++ b/cocos2d/core/components/CCAudioSource.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -45,8 +45,8 @@ var AudioSource = cc.Class({
ctor: function () {
// We can't require Audio here because jsb Audio is implemented outside the engine,
- // it can only take effect rely on overwriting cc.Audio
- this.audio = new cc.Audio();
+ // it can only take effect rely on overwriting cc._Audio
+ this.audio = new cc._Audio();
},
properties: {
@@ -61,6 +61,7 @@ var AudioSource = cc.Class({
default: false,
serializable: false
},
+ _firstlyEnabled: true,
/**
* !#en
@@ -77,7 +78,7 @@ var AudioSource = cc.Class({
isPlaying: {
get: function () {
var state = this.audio.getState();
- return state === cc.Audio.State.PLAYING;
+ return state === cc._Audio.State.PLAYING;
},
visible: false
},
@@ -94,25 +95,17 @@ var AudioSource = cc.Class({
return this._clip;
},
set: function (value) {
- if (typeof value === 'string') {
- // backward compatibility since 1.10
- cc.warnID(8401, 'cc.AudioSource', 'cc.AudioClip', 'AudioClip', 'cc.AudioClip', 'audio');
- let self = this;
- AudioClip._loadByUrl(value, function (err, clip) {
- if (clip) {
- self.clip = clip;
- }
- });
- return;
- }
-
if (value === this._clip) {
return;
}
+ if (!(value instanceof AudioClip)) {
+ return cc.error('Wrong type of AudioClip.');
+ }
this._clip = value;
this.audio.stop();
+ this.audio.src = this._clip;
if (this.preload) {
- this.audio.src = this._clip;
+ this._clip._ensureLoaded();
}
},
type: AudioClip,
@@ -195,23 +188,25 @@ var AudioSource = cc.Class({
animatable: false
},
+ /**
+ * !#en If set to true and AudioClip is a deferred load resource, the component will preload AudioClip in the onLoad phase.
+ * !#zh 如果设置为 true 且 AudioClip 为延迟加载资源,组件将在 onLoad 阶段预加载 AudioClip。
+ * @property preload
+ * @type {Boolean}
+ * @default false
+ */
preload: {
default: false,
animatable: false
}
},
- _ensureDataLoaded () {
- if (this.audio.src !== this._clip) {
- this.audio.src = this._clip;
- }
- },
-
_pausedCallback: function () {
- var audio = this.audio;
- if (audio.paused) return;
- this.audio.pause();
- this._pausedFlag = true;
+ var state = this.audio.getState();
+ if (state === cc._Audio.State.PLAYING) {
+ this.audio.pause();
+ this._pausedFlag = true;
+ }
},
_restoreCallback: function () {
@@ -222,15 +217,18 @@ var AudioSource = cc.Class({
},
onLoad: function () {
- this.audio.setVolume(this._mute ? 0 : this._volume);
- this.audio.setLoop(this._loop);
+ // this.audio.src is undefined, when the clip property is deserialized from the scene
+ if (!this.audio.src) {
+ this.audio.src = this._clip;
+ }
+ if (this.preload) {
+ this._clip._ensureLoaded();
+ }
},
onEnable: function () {
- if (this.preload) {
- this.audio.src = this._clip;
- }
- if (this.playOnLoad) {
+ if (this.playOnLoad && this._firstlyEnabled) {
+ this._firstlyEnabled = false;
this.play();
}
cc.game.on(cc.game.EVENT_HIDE, this._pausedCallback, this);
@@ -244,9 +242,7 @@ var AudioSource = cc.Class({
},
onDestroy: function () {
- this.stop();
this.audio.destroy();
- cc.audioEngine.uncache(this._clip);
},
/**
@@ -258,10 +254,8 @@ var AudioSource = cc.Class({
if ( !this._clip ) return;
var audio = this.audio;
- if (this._clip.loaded) {
- audio.stop();
- }
- this._ensureDataLoaded();
+ audio.setVolume(this._mute ? 0 : this._volume);
+ audio.setLoop(this._loop);
audio.setCurrentTime(0);
audio.play();
},
@@ -290,7 +284,6 @@ var AudioSource = cc.Class({
* @method resume
*/
resume: function () {
- this._ensureDataLoaded();
this.audio.resume();
},
diff --git a/cocos2d/core/components/CCBlockInputEvents.js b/cocos2d/core/components/CCBlockInputEvents.js
index aa236a2dbf9..6d55984f91f 100644
--- a/cocos2d/core/components/CCBlockInputEvents.js
+++ b/cocos2d/core/components/CCBlockInputEvents.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -49,7 +49,7 @@ const BlockInputEvents = cc.Class({
editor: {
menu: 'i18n:MAIN_MENU.component.ui/Block Input Events',
inspector: 'packages://inspector/inspectors/comps/block-input-events.js',
- help: 'i18n:COMPONENT.help_url.block-input-events',
+ help: 'i18n:COMPONENT.help_url.block_input_events',
},
onEnable () {
diff --git a/cocos2d/core/components/CCButton.js b/cocos2d/core/components/CCButton.js
index 0c3163fc45c..8f47c10a00e 100644
--- a/cocos2d/core/components/CCButton.js
+++ b/cocos2d/core/components/CCButton.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -25,7 +25,7 @@
****************************************************************************/
const Component = require('./CCComponent');
-const misc = require('../utils/misc');
+const GraySpriteState = require('../utils/gray-sprite-state');
/**
* !#en Enum for transition type.
@@ -61,47 +61,72 @@ let Transition = cc.Enum({
SCALE: 3
});
+const State = cc.Enum({
+ NORMAL: 0,
+ HOVER: 1,
+ PRESSED: 2,
+ DISABLED: 3,
+});
+
/**
* !#en
- * Button has 4 Transition types
- * When Button state changed:
- * If Transition type is Button.Transition.NONE, Button will do nothing
- * If Transition type is Button.Transition.COLOR, Button will change target's color
- * If Transition type is Button.Transition.SPRITE, Button will change target Sprite's sprite
- * If Transition type is Button.Transition.SCALE, Button will change target node's scale
+ * Button component. Can be pressed or clicked. Button has 4 Transition types:
+ *
+ * - Button.Transition.NONE // Button will do nothing
+ * - Button.Transition.COLOR // Button will change target's color
+ * - Button.Transition.SPRITE // Button will change target Sprite's sprite
+ * - Button.Transition.SCALE // Button will change target node's scale
+ *
+ * The button can bind events (but you must be on the button's node to bind events).
+ * The following events can be triggered on all platforms.
+ *
+ * - cc.Node.EventType.TOUCH_START // Press
+ * - cc.Node.EventType.TOUCH_MOVE // After pressing and moving
+ * - cc.Node.EventType.TOUCH_END // After pressing and releasing
+ * - cc.Node.EventType.TOUCH_CANCEL // Press to cancel
+ *
+ * The following events are only triggered on the PC platform:
+ *
+ * - cc.Node.EventType.MOUSE_DOWN
+ * - cc.Node.EventType.MOUSE_MOVE
+ * - cc.Node.EventType.MOUSE_ENTER
+ * - cc.Node.EventType.MOUSE_LEAVE
+ * - cc.Node.EventType.MOUSE_UP
+ * - cc.Node.EventType.MOUSE_WHEEL
*
- * Button will trigger 5 events:
- * Button.EVENT_TOUCH_DOWN
- * Button.EVENT_TOUCH_UP
- * Button.EVENT_HOVER_IN
- * Button.EVENT_HOVER_MOVE
- * Button.EVENT_HOVER_OUT
+ * User can get the current clicked node with 'event.target' from event object which is passed as parameter in the callback function of click event.
*
* !#zh
- * 按钮组件。可以被按下,或者点击。
+ * 按钮组件。可以被按下,或者点击。
*
- * 按钮可以通过修改 Transition 来设置按钮状态过渡的方式:
- * -Button.Transition.NONE // 不做任何过渡
- * -Button.Transition.COLOR // 进行颜色之间过渡
- * -Button.Transition.SPRITE // 进行精灵之间过渡
- * -Button.Transition.SCALE // 进行缩放过渡
+ * 按钮可以通过修改 Transition 来设置按钮状态过渡的方式:
+ *
+ * - Button.Transition.NONE // 不做任何过渡
+ * - Button.Transition.COLOR // 进行颜色之间过渡
+ * - Button.Transition.SPRITE // 进行精灵之间过渡
+ * - Button.Transition.SCALE // 进行缩放过渡
*
* 按钮可以绑定事件(但是必须要在按钮的 Node 上才能绑定事件):
- * // 以下事件可以在全平台上都触发
- * -cc.Node.EventType.TOUCH_START // 按下时事件
- * -cc.Node.EventType.TOUCH_Move // 按住移动后事件
- * -cc.Node.EventType.TOUCH_END // 按下后松开后事件
- * -cc.Node.EventType.TOUCH_CANCEL // 按下取消事件
- * // 以下事件只在 PC 平台上触发
- * -cc.Node.EventType.MOUSE_DOWN // 鼠标按下时事件
- * -cc.Node.EventType.MOUSE_MOVE // 鼠标按住移动后事件
- * -cc.Node.EventType.MOUSE_ENTER // 鼠标进入目标事件
- * -cc.Node.EventType.MOUSE_LEAVE // 鼠标离开目标事件
- * -cc.Node.EventType.MOUSE_UP // 鼠标松开事件
- * -cc.Node.EventType.MOUSE_WHEEL // 鼠标滚轮事件
- *
+ * 以下事件可以在全平台上都触发:
+ *
+ * - cc.Node.EventType.TOUCH_START // 按下时事件
+ * - cc.Node.EventType.TOUCH_MOVE // 按住移动后事件
+ * - cc.Node.EventType.TOUCH_END // 按下后松开后事件
+ * - cc.Node.EventType.TOUCH_CANCEL // 按下取消事件
+ *
+ * 以下事件只在 PC 平台上触发:
+ *
+ * - cc.Node.EventType.MOUSE_DOWN // 鼠标按下时事件
+ * - cc.Node.EventType.MOUSE_MOVE // 鼠标按住移动后事件
+ * - cc.Node.EventType.MOUSE_ENTER // 鼠标进入目标事件
+ * - cc.Node.EventType.MOUSE_LEAVE // 鼠标离开目标事件
+ * - cc.Node.EventType.MOUSE_UP // 鼠标松开事件
+ * - cc.Node.EventType.MOUSE_WHEEL // 鼠标滚轮事件
+ *
+ * 用户可以通过获取 __点击事件__ 回调函数的参数 event 的 target 属性获取当前点击对象。
* @class Button
* @extends Component
+ * @uses GraySpriteState
* @example
*
* // Add an event to the button.
@@ -119,6 +144,7 @@ let Transition = cc.Enum({
let Button = cc.Class({
name: 'cc.Button',
extends: Component,
+ mixins: [GraySpriteState],
ctor () {
this._pressed = false;
@@ -127,15 +153,15 @@ let Button = cc.Class({
this._toColor = null;
this._time = 0;
this._transitionFinished = true;
- this._fromScale = 1.0;
- this._toScale = 1.0;
- this._originalScale = 1.0;
+ // init _originalScale in __preload()
+ this._fromScale = cc.Vec2.ZERO;
+ this._toScale = cc.Vec2.ZERO;
+ this._originalScale = null;
- this._sprite = null;
+ this._graySpriteMaterial = null;
+ this._spriteMaterial = null;
- if (CC_EDITOR) {
- this._previousNormalSprite = null;
- }
+ this._sprite = null;
},
editor: CC_EDITOR && {
@@ -158,14 +184,7 @@ let Button = cc.Class({
interactable: {
default: true,
tooltip: CC_DEV && 'i18n:COMPONENT.button.interactable',
- notify (oldValue) {
- if (CC_EDITOR) {
- if (oldValue) {
- this._previousNormalSprite = this.normalSprite;
- } else {
- this.normalSprite = this._previousNormalSprite;
- }
- }
+ notify () {
this._updateState();
if (!this.interactable) {
@@ -193,7 +212,7 @@ let Button = cc.Class({
default: false,
tooltip: CC_DEV && 'i18n:COMPONENT.button.auto_gray_effect',
notify () {
- this._updateDisabledState();
+ this._updateDisabledState(true);
}
},
@@ -207,7 +226,11 @@ let Button = cc.Class({
default: Transition.NONE,
tooltip: CC_DEV && 'i18n:COMPONENT.button.transition',
type: Transition,
- animatable: false
+ animatable: false,
+ notify (oldValue) {
+ this._updateTransition(oldValue);
+ },
+ formerlySerializedAs: 'transition'
},
// color transition
@@ -218,10 +241,13 @@ let Button = cc.Class({
* @property {Color} normalColor
*/
normalColor: {
- default: cc.color(214, 214, 214),
+ default: cc.Color.WHITE,
displayName: 'Normal',
tooltip: CC_DEV && 'i18n:COMPONENT.button.normal_color',
notify () {
+ if (this.transition === Transition.Color && this._getButtonState() === State.NORMAL) {
+ this._getTarget().opacity = this.normalColor.a;
+ }
this._updateState();
}
},
@@ -235,6 +261,13 @@ let Button = cc.Class({
default: cc.color(211, 211, 211),
displayName: 'Pressed',
tooltip: CC_DEV && 'i18n:COMPONENT.button.pressed_color',
+ notify () {
+ if (this.transition === Transition.Color && this._getButtonState() === State.PRESSED) {
+ this._getTarget().opacity = this.pressedColor.a;
+ }
+ this._updateState();
+ },
+ formerlySerializedAs: 'pressedColor'
},
/**
@@ -246,6 +279,13 @@ let Button = cc.Class({
default: cc.Color.WHITE,
displayName: 'Hover',
tooltip: CC_DEV && 'i18n:COMPONENT.button.hover_color',
+ notify () {
+ if (this.transition === Transition.Color && this._getButtonState() === State.HOVER) {
+ this._getTarget().opacity = this.hoverColor.a;
+ }
+ this._updateState();
+ },
+ formerlySerializedAs: 'hoverColor'
},
/**
@@ -258,6 +298,9 @@ let Button = cc.Class({
displayName: 'Disabled',
tooltip: CC_DEV && 'i18n:COMPONENT.button.disabled_color',
notify () {
+ if (this.transition === Transition.Color && this._getButtonState() === State.DISABLED) {
+ this._getTarget().opacity = this.disabledColor.a;
+ }
this._updateState();
}
},
@@ -366,8 +409,11 @@ let Button = cc.Class({
default: null,
type: cc.Node,
tooltip: CC_DEV && "i18n:COMPONENT.button.target",
- notify () {
+ notify (oldValue) {
this._applyTarget();
+ if (oldValue && this.target !== oldValue) {
+ this._unregisterTargetEvent(oldValue);
+ }
}
},
@@ -388,23 +434,23 @@ let Button = cc.Class({
},
__preload () {
- if (!this.target) {
- this.target = this.node;
- }
this._applyTarget();
- this._updateState();
+ this._resetState();
},
_resetState () {
this._pressed = false;
this._hovered = false;
// // Restore button status
- let target = this.target;
+ let target = this._getTarget();
let transition = this.transition;
+ let originalScale = this._originalScale;
+
if (transition === Transition.COLOR && this.interactable) {
- target.color = this.normalColor;
- } else if (transition === Transition.SCALE) {
- target.scale = this._originalScale;
+ this._setTargetColor(this.normalColor);
+ }
+ else if (transition === Transition.SCALE && originalScale) {
+ target.setScale(originalScale.x, originalScale.y);
}
this._transitionFinished = true;
},
@@ -423,36 +469,119 @@ let Button = cc.Class({
if (this.disabledSprite) {
this.disabledSprite.ensureLoadTexture();
}
- //
+
if (!CC_EDITOR) {
- this._registerEvent();
- } else {
- this.node.on('spriteframe-changed', function (comp) {
- if (this.transition === Transition.SPRITE) {
- this.normalSprite = comp.spriteFrame;
- }
- }.bind(this));
+ this._registerNodeEvent();
}
+
+ this._updateState();
},
onDisable () {
this._resetState();
if (!CC_EDITOR) {
- this.node.off(cc.Node.EventType.TOUCH_START, this._onTouchBegan, this);
- this.node.off(cc.Node.EventType.TOUCH_MOVE, this._onTouchMove, this);
- this.node.off(cc.Node.EventType.TOUCH_END, this._onTouchEnded, this);
- this.node.off(cc.Node.EventType.TOUCH_CANCEL, this._onTouchCancel, this);
+ this._unregisterNodeEvent();
+ }
+ },
- this.node.off(cc.Node.EventType.MOUSE_ENTER, this._onMouseMoveIn, this);
- this.node.off(cc.Node.EventType.MOUSE_LEAVE, this._onMouseMoveOut, this);
- } else {
- this.node.off('spriteframe-changed');
+ _getTarget () {
+ return this.target ? this.target : this.node;
+ },
+
+ _onTargetSpriteFrameChanged (comp) {
+ if (this.transition === Transition.SPRITE) {
+ this._setCurrentStateSprite(comp.spriteFrame);
+ }
+ },
+
+ _onTargetColorChanged (color) {
+ if (this.transition === Transition.COLOR) {
+ this._setCurrentStateColor(color);
+ }
+ },
+
+ _onTargetScaleChanged () {
+ let target = this._getTarget();
+ // update _originalScale if target scale changed
+ if (this._originalScale) {
+ if (this.transition !== Transition.SCALE || this._transitionFinished) {
+ this._originalScale.x = target.scaleX;
+ this._originalScale.y = target.scaleY;
+ }
+ }
+ },
+
+ _setTargetColor (color) {
+ let target = this._getTarget();
+ let cloneColor = color.clone();
+ target.opacity = cloneColor.a;
+ cloneColor.a = 255; // don't set node opacity via node.color.a
+ target.color = cloneColor;
+ },
+
+ _getStateColor (state) {
+ switch (state) {
+ case State.NORMAL:
+ return this.normalColor;
+ case State.HOVER:
+ return this.hoverColor;
+ case State.PRESSED:
+ return this.pressedColor;
+ case State.DISABLED:
+ return this.disabledColor;
+ }
+ },
+
+ _getStateSprite (state) {
+ switch (state) {
+ case State.NORMAL:
+ return this.normalSprite;
+ case State.HOVER:
+ return this.hoverSprite;
+ case State.PRESSED:
+ return this.pressedSprite;
+ case State.DISABLED:
+ return this.disabledSprite;
+ }
+ },
+
+ _setCurrentStateColor (color) {
+ switch ( this._getButtonState() ) {
+ case State.NORMAL:
+ this.normalColor = color;
+ break;
+ case State.HOVER:
+ this.hoverColor = color;
+ break;
+ case State.PRESSED:
+ this.pressedColor = color;
+ break;
+ case State.DISABLED:
+ this.disabledColor = color;
+ break;
+ }
+ },
+
+ _setCurrentStateSprite (spriteFrame) {
+ switch ( this._getButtonState() ) {
+ case State.NORMAL:
+ this.normalSprite = spriteFrame;
+ break;
+ case State.HOVER:
+ this.hoverSprite = spriteFrame;
+ break;
+ case State.PRESSED:
+ this.pressedSprite = spriteFrame;
+ break;
+ case State.DISABLED:
+ this.disabledSprite = spriteFrame;
+ break;
}
},
update (dt) {
- let target = this.target;
+ let target = this._getTarget();
if (this._transitionFinished) return;
if (this.transition !== Transition.COLOR && this.transition !== Transition.SCALE) return;
@@ -462,20 +591,27 @@ let Button = cc.Class({
ratio = this.time / this.duration;
}
+ // clamp ratio
if (ratio >= 1) {
ratio = 1;
- this._transitionFinished = true;
}
if (this.transition === Transition.COLOR) {
- target.color = this._fromColor.lerp(this._toColor, ratio);
- } else if (this.transition === Transition.SCALE) {
- target.scale = misc.lerp(this._fromScale, this._toScale, ratio);
+ let color = this._fromColor.lerp(this._toColor, ratio);
+ this._setTargetColor(color);
+ }
+ // Skip if _originalScale is invalid
+ else if (this.transition === Transition.SCALE && this._originalScale) {
+ target.scale = this._fromScale.lerp(this._toScale, ratio);
+ }
+
+ if (ratio === 1) {
+ this._transitionFinished = true;
}
},
- _registerEvent () {
+ _registerNodeEvent () {
this.node.on(cc.Node.EventType.TOUCH_START, this._onTouchBegan, this);
this.node.on(cc.Node.EventType.TOUCH_MOVE, this._onTouchMove, this);
this.node.on(cc.Node.EventType.TOUCH_END, this._onTouchEnded, this);
@@ -485,6 +621,32 @@ let Button = cc.Class({
this.node.on(cc.Node.EventType.MOUSE_LEAVE, this._onMouseMoveOut, this);
},
+ _unregisterNodeEvent () {
+ this.node.off(cc.Node.EventType.TOUCH_START, this._onTouchBegan, this);
+ this.node.off(cc.Node.EventType.TOUCH_MOVE, this._onTouchMove, this);
+ this.node.off(cc.Node.EventType.TOUCH_END, this._onTouchEnded, this);
+ this.node.off(cc.Node.EventType.TOUCH_CANCEL, this._onTouchCancel, this);
+
+ this.node.off(cc.Node.EventType.MOUSE_ENTER, this._onMouseMoveIn, this);
+ this.node.off(cc.Node.EventType.MOUSE_LEAVE, this._onMouseMoveOut, this);
+ },
+
+ _registerTargetEvent (target) {
+ if (CC_EDITOR) {
+ target.on('spriteframe-changed', this._onTargetSpriteFrameChanged, this);
+ target.on(cc.Node.EventType.COLOR_CHANGED, this._onTargetColorChanged, this);
+ }
+ target.on(cc.Node.EventType.SCALE_CHANGED, this._onTargetScaleChanged, this);
+ },
+
+ _unregisterTargetEvent (target) {
+ if (CC_EDITOR) {
+ target.off('spriteframe-changed', this._onTargetSpriteFrameChanged, this);
+ target.off(cc.Node.EventType.COLOR_CHANGED, this._onTargetColorChanged, this);
+ }
+ target.off(cc.Node.EventType.SCALE_CHANGED, this._onTargetScaleChanged, this);
+ },
+
_getTargetSprite (target) {
let sprite = null;
if (target) {
@@ -494,10 +656,15 @@ let Button = cc.Class({
},
_applyTarget () {
- this._sprite = this._getTargetSprite(this.target);
- if (this.target) {
- this._originalScale = this.target.scale;
+ let target = this._getTarget();
+ this._sprite = this._getTargetSprite(target);
+ if (!this._originalScale) {
+ this._originalScale = cc.Vec2.ZERO;
}
+ this._originalScale.x = target.scaleX;
+ this._originalScale.y = target.scaleY;
+
+ this._registerTargetEvent(target);
},
// touch event handler
@@ -515,23 +682,27 @@ let Button = cc.Class({
// so we have to do hit test when touch moving
let touch = event.touch;
let hit = this.node._hitTest(touch.getLocation());
+ let target = this._getTarget();
+ let originalScale = this._originalScale;
- if (this.transition === Transition.SCALE && this.target) {
+ if (this.transition === Transition.SCALE && originalScale) {
if (hit) {
- this._fromScale = this._originalScale;
- this._toScale = this._originalScale * this.zoomScale;
+ this._fromScale.x = originalScale.x;
+ this._fromScale.y = originalScale.y;
+ this._toScale.x = originalScale.x * this.zoomScale;
+ this._toScale.y = originalScale.y * this.zoomScale;
this._transitionFinished = false;
} else {
this.time = 0;
this._transitionFinished = true;
- this.target.scale = this._originalScale;
+ target.setScale(originalScale.x, originalScale.y);
}
} else {
let state;
if (hit) {
- state = 'pressed';
+ state = State.PRESSED;
} else {
- state = 'normal';
+ state = State.NORMAL;
}
this._applyTransition(state);
}
@@ -584,28 +755,33 @@ let Button = cc.Class({
_getButtonState () {
let state;
if (!this.interactable) {
- state = 'disabled';
+ state = State.DISABLED;
}
else if (this._pressed) {
- state = 'pressed';
+ state = State.PRESSED;
}
else if (this._hovered) {
- state = 'hover';
+ state = State.HOVER;
}
else {
- state = 'normal';
+ state = State.NORMAL;
}
return state;
},
- _updateColorTransition (state) {
- let color = this[state + 'Color'];
- let target = this.target;
+ _updateColorTransitionImmediately (state) {
+ let color = this._getStateColor(state);
+ this._setTargetColor(color);
+ this._fromColor = color.clone();
+ this._toColor = color;
+ },
- if (CC_EDITOR) {
- target.color = color;
- }
- else {
+ _updateColorTransition (state) {
+ if (CC_EDITOR || state === State.DISABLED) {
+ this._updateColorTransitionImmediately(state);
+ } else {
+ let target = this._getTarget();
+ let color = this._getStateColor(state);
this._fromColor = target.color.clone();
this._toColor = color;
this.time = 0;
@@ -614,14 +790,14 @@ let Button = cc.Class({
},
_updateSpriteTransition (state) {
- let sprite = this[state + 'Sprite'];
+ let sprite = this._getStateSprite(state);
if (this._sprite && sprite) {
this._sprite.spriteFrame = sprite;
}
},
_updateScaleTransition (state) {
- if (state === 'pressed') {
+ if (state === State.PRESSED) {
this._zoomUp();
} else {
this._zoomBack();
@@ -629,19 +805,45 @@ let Button = cc.Class({
},
_zoomUp () {
- this._fromScale = this._originalScale;
- this._toScale = this._originalScale * this.zoomScale;
+ // skip before __preload()
+ if (!this._originalScale) {
+ return;
+ }
+
+ this._fromScale.x = this._originalScale.x;
+ this._fromScale.y = this._originalScale.y;
+ this._toScale.x = this._originalScale.x * this.zoomScale;
+ this._toScale.y = this._originalScale.y * this.zoomScale;
this.time = 0;
this._transitionFinished = false;
},
_zoomBack () {
- this._fromScale = this.target.scale;
- this._toScale = this._originalScale;
+ // skip before __preload()
+ if (!this._originalScale) {
+ return;
+ }
+
+ let target = this._getTarget();
+ this._fromScale.x = target.scaleX;
+ this._fromScale.y = target.scaleY;
+ this._toScale.x = this._originalScale.x;
+ this._toScale.y = this._originalScale.y;
this.time = 0;
this._transitionFinished = false;
},
+ _updateTransition (oldTransition) {
+ // Reset to normal data when change transition.
+ if (oldTransition === Transition.COLOR) {
+ this._updateColorTransitionImmediately(State.NORMAL);
+ }
+ else if (oldTransition === Transition.SPRITE) {
+ this._updateSpriteTransition(State.NORMAL);
+ }
+ this._updateState();
+ },
+
_applyTransition (state) {
let transition = this.transition;
if (transition === Transition.COLOR) {
@@ -654,22 +856,19 @@ let Button = cc.Class({
},
_resizeNodeToTargetNode: CC_EDITOR && function () {
- if (this.target) {
- this.node.setContentSize(this.target.getContentSize());
- }
+ this.node.setContentSize(this._getTarget().getContentSize());
},
- _updateDisabledState () {
- if (this._sprite) {
- if (this.enableAutoGrayEffect) {
- if (!(this.transition === Transition.SPRITE && this.disabledSprite)) {
- if (!this.interactable) {
- this._sprite.setState(cc.Sprite.State.GRAY);
- return;
- }
- }
+ _updateDisabledState (force) {
+ if (!this._sprite) return;
+
+ if (this.enableAutoGrayEffect || force) {
+ let useGrayMaterial = false;
+
+ if (!(this.transition === Transition.SPRITE && this.disabledSprite)) {
+ useGrayMaterial = this.enableAutoGrayEffect && !this.interactable;
}
- this._sprite.setState(cc.Sprite.State.NORMAL);
+ this._switchGrayMaterial(useGrayMaterial, this._sprite);
}
}
});
diff --git a/cocos2d/core/components/CCCanvas.js b/cocos2d/core/components/CCCanvas.js
index a627b8b3b3b..8c11bba9eaf 100644
--- a/cocos2d/core/components/CCCanvas.js
+++ b/cocos2d/core/components/CCCanvas.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -27,8 +27,24 @@
var Camera = require('../camera/CCCamera');
var Component = require('./CCComponent');
+// Screen adaptation strategy for Canvas + Widget
+function resetWidgetComponent (canvas) {
+ let widget = canvas.node.getComponent(cc.Widget);
+ if (!widget) {
+ widget = canvas.node.addComponent(cc.Widget);
+ }
+ widget.isAlignTop = true;
+ widget.isAlignBottom = true;
+ widget.isAlignLeft = true;
+ widget.isAlignRight = true;
+ widget.top = 0;
+ widget.bottom = 0;
+ widget.left = 0;
+ widget.right = 0;
+}
+
/**
- * !#zh: 作为 UI 根节点,为所有子节点提供视窗四边的位置信息以供对齐,另外提供屏幕适配策略接口,方便从编辑器设置。
+ * !#zh 作为 UI 根节点,为所有子节点提供视窗四边的位置信息以供对齐,另外提供屏幕适配策略接口,方便从编辑器设置。
* 注:由于本节点的尺寸会跟随屏幕拉伸,所以 anchorPoint 只支持 (0.5, 0.5),否则适配不同屏幕时坐标会有偏差。
*
* @class Canvas
@@ -47,6 +63,7 @@ var Canvas = cc.Class({
resetInEditor: CC_EDITOR && function () {
_Scene._applyCanvasPreferences(this);
+ resetWidgetComponent(this);
},
statics: {
@@ -76,7 +93,6 @@ var Canvas = cc.Class({
this._designResolution.width = value.width;
this._designResolution.height = value.height;
this.applySettings();
- this.alignWithScreen();
},
tooltip: CC_DEV && 'i18n:COMPONENT.canvas.design_resolution'
},
@@ -98,7 +114,6 @@ var Canvas = cc.Class({
if (this._fitHeight !== value) {
this._fitHeight = value;
this.applySettings();
- this.alignWithScreen();
}
},
tooltip: CC_DEV && 'i18n:COMPONENT.canvas.fit_height'
@@ -118,15 +133,18 @@ var Canvas = cc.Class({
if (this._fitWidth !== value) {
this._fitWidth = value;
this.applySettings();
- this.alignWithScreen();
}
},
tooltip: CC_DEV && 'i18n:COMPONENT.canvas.fit_width'
}
},
- ctor: function () {
- this._thisOnResized = this.alignWithScreen.bind(this);
+ // fit canvas node to design resolution
+ _fitDesignResolution: CC_EDITOR && function () {
+ // TODO: support paddings of locked widget
+ var designSize = cc.engine.getDesignResolutionSize();
+ this.node.setPosition(designSize.width * 0.5, designSize.height * 0.5);
+ this.node.setContentSize(designSize);
},
__preload: function () {
@@ -136,55 +154,48 @@ var Canvas = cc.Class({
}
if (Canvas.instance) {
- return cc.errorID(6700,
+ return cc.warnID(6700,
this.node.name, Canvas.instance.node.name);
}
Canvas.instance = this;
- if (CC_EDITOR) {
- cc.engine.on('design-resolution-changed', this._thisOnResized);
+ // Align node to fit the screen
+ this.applySettings();
+
+ // Stretch to matched size during the scene initialization
+ let widget = this.getComponent(cc.Widget);
+ if (widget) {
+ widget.updateAlignment();
}
- else {
- if (cc.sys.isMobile) {
- window.addEventListener('resize', this._thisOnResized);
- }
- else {
- cc.view.on('canvas-resize', this._thisOnResized);
- }
+ else if (CC_EDITOR) {
+ this._fitDesignResolution();
}
- this.applySettings();
- this.alignWithScreen();
+ // Constantly align canvas node in edit mode
+ if (CC_EDITOR) {
+ cc.director.on(cc.Director.EVENT_AFTER_UPDATE, this._fitDesignResolution, this);
+ cc.engine.on('design-resolution-changed', this._fitDesignResolution, this);
+ }
+ },
- // Camera could be removed in canvas render mode
- let cameraNode = cc.find('Main Camera', this.node);
- if (!cameraNode) {
- cameraNode = new cc.Node('Main Camera');
+ start () {
+ if (!Camera.main && cc.game.renderType !== cc.game.RENDER_TYPE_CANVAS) {
+ // Create default Main Camera
+ let cameraNode = new cc.Node('Main Camera');
cameraNode.parent = this.node;
cameraNode.setSiblingIndex(0);
- }
- let camera = cameraNode.getComponent(Camera);
- if (!camera) {
- camera = cameraNode.addComponent(Camera);
+ let camera = cameraNode.addComponent(Camera);
let ClearFlags = Camera.ClearFlags;
camera.clearFlags = ClearFlags.COLOR | ClearFlags.DEPTH | ClearFlags.STENCIL;
camera.depth = -1;
}
- Camera.main = camera;
},
onDestroy: function () {
if (CC_EDITOR) {
- cc.engine.off('design-resolution-changed', this._thisOnResized);
- }
- else {
- if (cc.sys.isMobile) {
- window.removeEventListener('resize', this._thisOnResized);
- }
- else {
- cc.view.off('canvas-resize', this._thisOnResized);
- }
+ cc.director.off(cc.Director.EVENT_AFTER_UPDATE, this._fitDesignResolution, this);
+ cc.engine.off('design-resolution-changed', this._fitDesignResolution, this);
}
if (Canvas.instance === this) {
@@ -192,31 +203,6 @@ var Canvas = cc.Class({
}
},
- //
-
- alignWithScreen: function () {
- var designSize, nodeSize;
- if (CC_EDITOR) {
- nodeSize = designSize = cc.engine.getDesignResolutionSize();
- this.node.setPosition(designSize.width * 0.5, designSize.height * 0.5);
- }
- else {
- var canvasSize = nodeSize = cc.visibleRect;
- designSize = cc.view.getDesignResolutionSize();
- var clipTopRight = !this.fitHeight && !this.fitWidth;
- var offsetX = 0;
- var offsetY = 0;
- if (clipTopRight) {
- // offset the canvas to make it in the center of screen
- offsetX = (designSize.width - canvasSize.width) * 0.5;
- offsetY = (designSize.height - canvasSize.height) * 0.5;
- }
- this.node.setPosition(canvasSize.width * 0.5 + offsetX, canvasSize.height * 0.5 + offsetY);
- }
- this.node.width = nodeSize.width;
- this.node.height = nodeSize.height;
- },
-
applySettings: function () {
var ResolutionPolicy = cc.ResolutionPolicy;
var policy;
diff --git a/cocos2d/core/components/CCComponent.js b/cocos2d/core/components/CCComponent.js
index 9775a43a2eb..7a9b69a5fcb 100644
--- a/cocos2d/core/components/CCComponent.js
+++ b/cocos2d/core/components/CCComponent.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -31,12 +31,14 @@ var idGenerater = new (require('../platform/id-generater'))('Comp');
var IsOnEnableCalled = CCObject.Flags.IsOnEnableCalled;
var IsOnLoadCalled = CCObject.Flags.IsOnLoadCalled;
+var ActionManagerExist = !!cc.ActionManager;
+
/**
* !#en
* Base class for everything attached to Node(Entity).
*
* NOTE: Not allowed to use construction parameters for Component's subclasses,
- * because Component is created by the engine.
+ * because Component is created by the engine.
* !#zh
* 所有附加到节点的基类。
*
@@ -50,14 +52,17 @@ var Component = cc.Class({
extends: CCObject,
ctor: CC_EDITOR ? function () {
- if (window._Scene && _Scene.AssetsWatcher) {
+ if ((typeof _Scene !== "undefined") && _Scene.AssetsWatcher) {
_Scene.AssetsWatcher.initComponent(this);
}
this._id = Editor.Utils.UuidUtils.uuid();
/**
+ * !#en
* Register all related EventTargets,
- * all event callbacks will be removed in _onPreDestroy
+ * all event callbacks will be removed in `_onPreDestroy`.
+ * !#zh
+ * 注册所有相关的 EventTargets,所有事件回调将在 `_onPreDestroy` 中删除。
* @property {Array} __eventTargets
* @private
*/
@@ -176,7 +181,8 @@ var Component = cc.Class({
}
}
},
- visible: false
+ visible: false,
+ animatable: true
},
/**
@@ -190,7 +196,7 @@ var Component = cc.Class({
*/
enabledInHierarchy: {
get () {
- return (this._objFlags & IsOnEnableCalled) > 0;
+ return this._enabled && this.node._activeInHierarchy;
},
visible: false
},
@@ -233,6 +239,7 @@ var Component = cc.Class({
* !#zh 如果该组件启用,则每帧调用 LateUpdate。
* 该方法为生命周期方法,父类未必会有实现。并且你只能在该方法内部调用父类的实现,不可在其它地方直接调用该方法。
* @method lateUpdate
+ * @param {Number} dt - the delta time in seconds it took to complete the last frame
* @protected
*/
lateUpdate: null,
@@ -462,16 +469,10 @@ var Component = cc.Class({
*
* 如果组件包含了“内部状态”(不在 CCClass 属性中定义的临时成员变量),那么你可能需要实现该方法。
*
- * 编辑器执行撤销/重做操作时,将调用组件的 get set 来录制和还原组件的状态。
- * 然而,在极端的情况下,它可能无法良好运作。
- * 那么你就应该实现这个方法,手动根据组件的属性同步“内部状态”。
- * 一旦你实现这个方法,当用户撤销或重做时,组件的所有 get set 都不会再被调用。
- * 这意味着仅仅指定了默认值的属性将被编辑器记录和还原。
+ * 编辑器执行撤销/重做操作时,将调用组件的 get set 来录制和还原组件的状态。然而,在极端的情况下,它可能无法良好运作。
+ * 那么你就应该实现这个方法,手动根据组件的属性同步“内部状态”。一旦你实现这个方法,当用户撤销或重做时,组件的所有 get set 都不会再被调用。这意味着仅仅指定了默认值的属性将被编辑器记录和还原。
*
- * 同样的,编辑可能无法在极端情况下正确地重置您的组件。
- * 于是如果你需要支持组件重置菜单,你需要在该方法中手工同步组件属性到“内部状态”。
- * 一旦你实现这个方法,组件的所有 get set 都不会在重置操作时被调用。
- * 这意味着仅仅指定了默认值的属性将被编辑器重置。
+ * 同样的,编辑可能无法在极端情况下正确地重置您的组件。如果你需要支持组件重置菜单,则需要在该方法中手工同步组件属性到“内部状态”。一旦你实现这个方法,组件的所有 get set 都不会在重置操作时被调用。这意味着仅仅指定了默认值的属性将被编辑器重置。
*
* 此方法仅在编辑器下会被调用。
* @method onRestore
@@ -496,12 +497,16 @@ var Component = cc.Class({
},
_onPreDestroy () {
+ if (ActionManagerExist) {
+ cc.director.getActionManager().removeAllActionsFromTarget(this);
+ }
+
// Schedules
this.unscheduleAllCallbacks();
// Remove all listeners
var eventTargets = this.__eventTargets;
- for (var i = 0, l = eventTargets.length; i < l; ++i) {
+ for (var i = eventTargets.length - 1; i >= 0; --i) {
var target = eventTargets[i];
target && target.targetOff(this);
}
@@ -540,7 +545,7 @@ var Component = cc.Class({
* @param {function} callback The callback function
* @param {Number} [interval=0] Tick interval in seconds. 0 means tick every frame.
* @param {Number} [repeat=cc.macro.REPEAT_FOREVER] The selector will be executed (repeat + 1) times, you can use cc.macro.REPEAT_FOREVER for tick infinitely.
- * @param {Number} [delay=0] The amount of time that the first tick will wait before execution.
+ * @param {Number} [delay=0] The amount of time that the first tick will wait before execution. Unit: s
* @example
* var timeCallback = function (dt) {
* cc.log("time: " + dt);
@@ -549,9 +554,10 @@ var Component = cc.Class({
*/
schedule (callback, interval, repeat, delay) {
cc.assertID(callback, 1619);
- cc.assertID(interval >= 0, 1620);
interval = interval || 0;
+ cc.assertID(interval >= 0, 1620);
+
repeat = isNaN(repeat) ? cc.macro.REPEAT_FOREVER : repeat;
delay = delay || 0;
@@ -572,7 +578,7 @@ var Component = cc.Class({
* @method scheduleOnce
* @see cc.Node#schedule
* @param {function} callback A function wrapped as a selector
- * @param {Number} [delay=0] The amount of time that the first tick will wait before execution.
+ * @param {Number} [delay=0] The amount of time that the first tick will wait before execution. Unit: s
* @example
* var timeCallback = function (dt) {
* cc.log("time: " + dt);
@@ -603,7 +609,7 @@ var Component = cc.Class({
* !#en
* unschedule all scheduled callback functions: custom callback functions, and the 'update' callback function.
* Actions are not affected by this method.
- * !#zh 取消调度所有已调度的回调函数:定制的回调函数以及 'update' 回调函数。动作不受此方法影响。
+ * !#zh 取消调度所有已调度的回调函数:定制的回调函数以及 `update` 回调函数。动作不受此方法影响。
* @method unscheduleAllCallbacks
* @example
* this.unscheduleAllCallbacks();
@@ -615,6 +621,7 @@ var Component = cc.Class({
Component._requireComponent = null;
Component._executionOrder = 0;
+if (CC_EDITOR && CC_PREVIEW) Component._disallowMultiple = null;
if (CC_EDITOR || CC_TEST) {
@@ -622,7 +629,6 @@ if (CC_EDITOR || CC_TEST) {
Component._executeInEditMode = false;
Component._playOnFocus = false;
- Component._disallowMultiple = null;
Component._help = '';
// NON-INHERITED STATIC MEMBERS
@@ -644,7 +650,7 @@ if (CC_EDITOR || CC_TEST) {
};
}
-// we make this non-enumerable, to prevent inherited by sub classes.
+// We make this non-enumerable, to prevent inherited by sub classes.
js.value(Component, '_registerEditorProps', function (cls, props) {
var reqComp = props.requireComponent;
if (reqComp) {
@@ -654,6 +660,9 @@ js.value(Component, '_registerEditorProps', function (cls, props) {
if (order && typeof order === 'number') {
cls._executionOrder = order;
}
+ if ((CC_EDITOR || CC_PREVIEW) && 'disallowMultiple' in props) {
+ cls._disallowMultiple = cls;
+ }
if (CC_EDITOR || CC_TEST) {
var name = cc.js.getClassName(cls);
for (var key in props) {
@@ -687,12 +696,9 @@ js.value(Component, '_registerEditorProps', function (cls, props) {
Component._addMenuItem(cls, val, props.menuPriority);
break;
- case 'disallowMultiple':
- cls._disallowMultiple = cls;
- break;
-
case 'requireComponent':
case 'executionOrder':
+ case 'disallowMultiple':
// skip here
break;
diff --git a/cocos2d/core/components/CCComponentEventHandler.js b/cocos2d/core/components/CCComponentEventHandler.js
index c05e7cafaa9..80bb8c41815 100644
--- a/cocos2d/core/components/CCComponentEventHandler.js
+++ b/cocos2d/core/components/CCComponentEventHandler.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -35,19 +35,29 @@
* 并可通过 emit 方法调用目标函数。
* @class Component.EventHandler
* @example
+ * // Let's say we have a MainMenu component on newTarget
+ * // file: MainMenu.js
+ * cc.Class({
+ * extends: cc.Component,
+ * // sender: the node MainMenu.js belongs to
+ * // eventType: CustomEventData
+ * onClick (sender, eventType) {
+ * cc.log('click');
+ * }
+ * })
* // Create new EventHandler
* var eventHandler = new cc.Component.EventHandler();
* eventHandler.target = newTarget;
* eventHandler.component = "MainMenu";
- * eventHandler.handler = "OnClick";
+ * eventHandler.handler = "onClick";
* eventHandler.customEventData = "my data";
*/
cc.Component.EventHandler = cc.Class({
name: 'cc.ClickEvent',
properties: {
/**
- * !#en Event target
- * !#zh 目标节点
+ * !#en the node that contains target callback, such as the node example script belongs to
+ * !#zh 事件响应函数所在节点 ,比如例子中脚本归属的节点本身
* @property target
* @type {Node}
* @default null
@@ -57,8 +67,8 @@ cc.Component.EventHandler = cc.Class({
type: cc.Node,
},
/**
- * !#en Component name
- * !#zh 目标组件名
+ * !#en name of the component(script) that contains target callback, such as the name 'MainMenu' of script in example
+ * !#zh 事件响应函数所在组件名(脚本名), 比如例子中的脚本名 'MainMenu'
* @property component
* @type {String}
* @default ''
@@ -77,8 +87,8 @@ cc.Component.EventHandler = cc.Class({
},
},
/**
- * !#en Event handler
- * !#zh 响应事件函数名
+ * !#en Event handler, such as function's name 'onClick' in example
+ * !#zh 响应事件函数名,比如例子中的 'onClick'
* @property handler
* @type {String}
* @default ''
@@ -88,8 +98,8 @@ cc.Component.EventHandler = cc.Class({
},
/**
- * !#en Custom Event Data
- * !#zh 自定义事件数据
+ * !#en Custom Event Data, such as 'eventType' in example
+ * !#zh 自定义事件数据,比如例子中的 eventType
* @property customEventData
* @default ''
* @type {String}
diff --git a/cocos2d/core/components/CCLabel.js b/cocos2d/core/components/CCLabel.js
index 2fe08e88a3c..2bee9d5201d 100644
--- a/cocos2d/core/components/CCLabel.js
+++ b/cocos2d/core/components/CCLabel.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -26,9 +26,10 @@
const macro = require('../platform/CCMacro');
const RenderComponent = require('./CCRenderComponent');
-const renderEngine = require('../renderer/render-engine');
-const RenderFlow = require('../renderer/render-flow');
-const SpriteMaterial = renderEngine.SpriteMaterial;
+const Material = require('../assets/material/CCMaterial');
+const LabelFrame = require('../renderer/utils/label/label-frame');
+const BlendFunc = require('../utils/blend-func');
+const deleteFromDynamicAtlas = require('../renderer/utils/utils').deleteFromDynamicAtlas;
/**
* !#en Enum for text alignment.
@@ -90,8 +91,8 @@ const VerticalAlign = macro.VerticalTextAlignment;
* @property {Number} CLAMP
*/
/**
- * !#en In SHRINK mode, the font size will change dynamically to adapt the content size.
- * !#zh SHRINK 模式,字体大小会动态变化,以适应内容大小。
+ * !#en In SHRINK mode, the font size will change dynamically to adapt the content size. This mode may takes up more CPU resources when the label is refreshed.
+ * !#zh SHRINK 模式,字体大小会动态变化,以适应内容大小。这个模式在文本刷新的时候可能会占用较多 CPU 资源。
* @property {Number} SHRINK
*/
/**
@@ -127,15 +128,46 @@ const Overflow = cc.Enum({
* @property {Number} SystemFont
*/
+/**
+ * !#en Enum for cache mode.
+ * !#zh CacheMode 类型
+ * @enum Label.CacheMode
+ */
+ /**
+ * !#en Do not do any caching.
+ * !#zh 不做任何缓存。
+ * @property {Number} NONE
+ */
+/**
+ * !#en In BITMAP mode, cache the label as a static image and add it to the dynamic atlas for batch rendering, and can batching with Sprites using broken images.
+ * !#zh BITMAP 模式,将 label 缓存成静态图像并加入到动态图集,以便进行批次合并,可与使用碎图的 Sprite 进行合批(注:动态图集在 Chrome 以及微信小游戏暂时关闭,该功能无效)。
+ * @property {Number} BITMAP
+ */
+/**
+ * !#en In CHAR mode, split text into characters and cache characters into a dynamic atlas which the size of 2048*2048.
+ * !#zh CHAR 模式,将文本拆分为字符,并将字符缓存到一张单独的大小为 2048*2048 的图集中进行重复使用,不再使用动态图集(注:当图集满时将不再进行缓存,暂时不支持 SHRINK 自适应文本尺寸(后续完善))。
+ * @property {Number} CHAR
+ */
+const CacheMode = cc.Enum({
+ NONE: 0,
+ BITMAP: 1,
+ CHAR: 2,
+});
+
+const BOLD_FLAG = 1 << 0;
+const ITALIC_FLAG = 1 << 1;
+const UNDERLINE_FLAG = 1 << 2;
+
/**
* !#en The Label Component.
* !#zh 文字标签组件
* @class Label
- * @extends Component
+ * @extends RenderComponent
*/
let Label = cc.Class({
name: 'cc.Label',
extends: RenderComponent,
+ mixins: [BlendFunc],
ctor () {
if (CC_EDITOR) {
@@ -145,7 +177,16 @@ let Label = cc.Class({
this._actualFontSize = 0;
this._assemblerData = null;
+ this._frame = null;
this._ttfTexture = null;
+ this._letterTexture = null;
+
+ if (cc.game.renderType === cc.game.RENDER_TYPE_CANVAS) {
+ this._updateMaterial = this._updateMaterialCanvas;
+ }
+ else {
+ this._updateMaterial = this._updateMaterialWebgl;
+ }
},
editor: CC_EDITOR && {
@@ -155,8 +196,6 @@ let Label = cc.Class({
},
properties: {
- _useOriginalSize: true,
-
/**
* !#en Content string of label.
* !#zh 标签显示的文本内容。
@@ -172,10 +211,10 @@ let Label = cc.Class({
},
set (value) {
let oldValue = this._string;
- this._string = value.toString();
+ this._string = '' + value;
if (this.string !== oldValue) {
- this._updateRenderData();
+ this.setVertsDirty();
}
this._checkStringEmpty();
@@ -195,7 +234,7 @@ let Label = cc.Class({
tooltip: CC_DEV && 'i18n:COMPONENT.label.horizontal_align',
notify (oldValue) {
if (this.horizontalAlign === oldValue) return;
- this._updateRenderData();
+ this.setVertsDirty();
},
animatable: false
},
@@ -211,7 +250,7 @@ let Label = cc.Class({
tooltip: CC_DEV && 'i18n:COMPONENT.label.vertical_align',
notify (oldValue) {
if (this.verticalAlign === oldValue) return;
- this._updateRenderData();
+ this.setVertsDirty();
},
animatable: false
},
@@ -228,7 +267,8 @@ let Label = cc.Class({
readonly: true,
get () {
return this._actualFontSize;
- }
+ },
+ tooltip: CC_DEV && 'i18n:COMPONENT.label.actualFontSize',
},
_fontSize: 40,
@@ -245,8 +285,9 @@ let Label = cc.Class({
if (this._fontSize === value) return;
this._fontSize = value;
- this._updateRenderData();
+ this.setVertsDirty();
},
+ range: [0, 512],
tooltip: CC_DEV && 'i18n:COMPONENT.label.font_size',
},
@@ -260,7 +301,7 @@ let Label = cc.Class({
tooltip: CC_DEV && 'i18n:COMPONENT.label.font_family',
notify (oldValue) {
if (this.fontFamily === oldValue) return;
- this._updateRenderData();
+ this.setVertsDirty();
},
animatable: false
},
@@ -278,7 +319,7 @@ let Label = cc.Class({
set (value) {
if (this._lineHeight === value) return;
this._lineHeight = value;
- this._updateRenderData();
+ this.setVertsDirty();
},
tooltip: CC_DEV && 'i18n:COMPONENT.label.line_height',
},
@@ -293,7 +334,7 @@ let Label = cc.Class({
tooltip: CC_DEV && 'i18n:COMPONENT.label.overflow',
notify (oldValue) {
if (this.overflow === oldValue) return;
- this._updateRenderData();
+ this.setVertsDirty();
},
animatable: false
},
@@ -312,7 +353,7 @@ let Label = cc.Class({
if (this._enableWrapText === value) return;
this._enableWrapText = value;
- this._updateRenderData();
+ this.setVertsDirty();
},
animatable: false,
tooltip: CC_DEV && 'i18n:COMPONENT.label.wrap',
@@ -341,28 +382,13 @@ let Label = cc.Class({
if (CC_EDITOR && value) {
this._userDefinedFont = value;
}
-
this._N$file = value;
- this._bmFontOriginalSize = -1;
if (value && this._isSystemFontUsed)
this._isSystemFontUsed = false;
- if ( typeof value === 'string' ) {
- cc.warnID(4000);
- }
-
- if (value instanceof cc.BitmapFont) {
- this._bmFontOriginalSize = value.fontSize;
- }
+ if (!this.enabledInHierarchy) return;
- if (this._renderData) {
- this.destroyRenderData(this._renderData);
- this._renderData = null;
- }
- this._fontAtlas = null;
- this._updateAssembler();
- this._activateMaterial(true);
- this._updateRenderData();
+ this._forceUpdateRenderData();
},
type: cc.Font,
tooltip: CC_DEV && 'i18n:COMPONENT.label.font',
@@ -374,7 +400,7 @@ let Label = cc.Class({
/**
* !#en Whether use system font name or not.
* !#zh 是否使用系统字体。
- * @property {Boolean} isSystemFontUsed
+ * @property {Boolean} useSystemFont
*/
useSystemFont: {
get () {
@@ -382,29 +408,23 @@ let Label = cc.Class({
},
set (value) {
if (this._isSystemFontUsed === value) return;
-
- this.destroyRenderData(this._renderData);
- this._renderData = null;
-
+ this._isSystemFontUsed = !!value;
if (CC_EDITOR) {
- if (!value && this._isSystemFontUsed && this._userDefinedFont) {
+ if (!value && this._userDefinedFont) {
this.font = this._userDefinedFont;
this.spacingX = this._spacingX;
return;
}
}
- this._isSystemFontUsed = !!value;
if (value) {
this.font = null;
- this._updateAssembler();
- this._updateRenderData();
- this._checkStringEmpty();
- }
- else if (!this._userDefinedFont) {
- this.disableRender();
- }
+ if (!this.enabledInHierarchy) return;
+
+ this._forceUpdateRenderData();
+ }
+ this.markForValidate();
},
animatable: false,
tooltip: CC_DEV && 'i18n:COMPONENT.label.system_font',
@@ -412,35 +432,151 @@ let Label = cc.Class({
_bmFontOriginalSize: {
displayName: 'BMFont Original Size',
- default: -1,
- serializable: false,
- readonly: true,
+ get () {
+ if (this._N$file instanceof cc.BitmapFont) {
+ return this._N$file.fontSize;
+ }
+ else {
+ return -1;
+ }
+ },
visible: true,
animatable: false
},
_spacingX: 0,
+
+ /**
+ * !#en The spacing of the x axis between characters, only take Effect when using bitmap fonts.
+ * !#zh 文字之间 x 轴的间距,仅在使用位图字体时生效。
+ * @property {Number} spacingX
+ */
spacingX: {
get () {
return this._spacingX;
},
set (value) {
this._spacingX = value;
- this._updateRenderData();
- }
+ this.setVertsDirty();
+ },
+ tooltip: CC_DEV && 'i18n:COMPONENT.label.spacingX',
},
- _isBold: {
- default: false,
- serializable: false,
+ //For compatibility with v2.0.x temporary reservation.
+ _batchAsBitmap: false,
+
+ /**
+ * !#en The cache mode of label. This mode only supports system fonts.
+ * !#zh 文本缓存模式, 该模式只支持系统字体。
+ * @property {Label.CacheMode} cacheMode
+ */
+ cacheMode: {
+ default: CacheMode.NONE,
+ type: CacheMode,
+ tooltip: CC_DEV && 'i18n:COMPONENT.label.cacheMode',
+ notify (oldValue) {
+ if (this.cacheMode === oldValue) return;
+
+ if (oldValue === CacheMode.BITMAP && !(this.font instanceof cc.BitmapFont)) {
+ this._frame && this._frame._resetDynamicAtlasFrame();
+ }
+
+ if (oldValue === CacheMode.CHAR) {
+ this._ttfTexture = null;
+ }
+
+ if (!this.enabledInHierarchy) return;
+
+ this._forceUpdateRenderData();
+ },
+ animatable: false
},
- _isItalic: {
- default: false,
- serializable: false,
+
+ _styleFlags: 0,
+
+ /**
+ * !#en Whether enable bold.
+ * !#zh 是否启用黑体。
+ * @property {Boolean} enableBold
+ */
+ enableBold: {
+ get () {
+ return !!(this._styleFlags & BOLD_FLAG);
+ },
+ set (value) {
+ if (value) {
+ this._styleFlags |= BOLD_FLAG;
+ } else {
+ this._styleFlags &= ~BOLD_FLAG;
+ }
+
+ this.setVertsDirty();
+ },
+ animatable: false,
+ tooltip: CC_DEV && 'i18n:COMPONENT.label.bold'
},
- _isUnderline: {
- default: false,
- serializable: false,
+
+ /**
+ * !#en Whether enable italic.
+ * !#zh 是否启用斜体。
+ * @property {Boolean} enableItalic
+ */
+ enableItalic: {
+ get () {
+ return !!(this._styleFlags & ITALIC_FLAG);
+ },
+ set (value) {
+ if (value) {
+ this._styleFlags |= ITALIC_FLAG;
+ } else {
+ this._styleFlags &= ~ITALIC_FLAG;
+ }
+
+ this.setVertsDirty();
+ },
+ animatable: false,
+ tooltip: CC_DEV && 'i18n:COMPONENT.label.italic'
+ },
+
+ /**
+ * !#en Whether enable underline.
+ * !#zh 是否启用下划线。
+ * @property {Boolean} enableUnderline
+ */
+ enableUnderline: {
+ get () {
+ return !!(this._styleFlags & UNDERLINE_FLAG);
+ },
+ set (value) {
+ if (value) {
+ this._styleFlags |= UNDERLINE_FLAG;
+ } else {
+ this._styleFlags &= ~UNDERLINE_FLAG;
+ }
+
+ this.setVertsDirty();
+ },
+ animatable: false,
+ tooltip: CC_DEV && 'i18n:COMPONENT.label.underline'
+ },
+
+ _underlineHeight: 0,
+ /**
+ * !#en The height of underline.
+ * !#zh 下划线高度。
+ * @property {Number} underlineHeight
+ */
+ underlineHeight: {
+ get () {
+ return this._underlineHeight;
+ },
+ set (value) {
+ if (this._underlineHeight === value) return;
+
+ this._underlineHeight = value;
+ this.setVertsDirty();
+ },
+ tooltip: CC_DEV && 'i18n:COMPONENT.label.underline_height',
},
},
@@ -448,38 +584,57 @@ let Label = cc.Class({
HorizontalAlign: HorizontalAlign,
VerticalAlign: VerticalAlign,
Overflow: Overflow,
- },
+ CacheMode: CacheMode,
- onEnable () {
- this._super();
+ _shareAtlas: null,
+ /**
+ * !#zh 需要保证当前场景中没有使用CHAR缓存的Label才可以清除,否则已渲染的文字没有重新绘制会不显示
+ * !#en It can be cleared that need to ensure there is not use the CHAR cache in the current scene. Otherwise, the rendered text will not be displayed without repainting.
+ * @method clearCharCache
+ * @static
+ */
+ clearCharCache () {
+ if (Label._shareAtlas) {
+ Label._shareAtlas.clearAllCache();
+ }
+ }
+ },
- // TODO: Hack for barbarians
- if (!this.font && !this._isSystemFontUsed) {
- this.useSystemFont = true;
+ onLoad () {
+ // For compatibility with v2.0.x temporary reservation.
+ if (this._batchAsBitmap && this.cacheMode === CacheMode.NONE) {
+ this.cacheMode = CacheMode.BITMAP;
+ this._batchAsBitmap = false;
}
- // Reapply default font family if necessary
- if (this.useSystemFont && !this.fontFamily) {
- this.fontFamily = 'Arial';
+
+ if (cc.game.renderType === cc.game.RENDER_TYPE_CANVAS) {
+ // CacheMode is not supported in Canvas.
+ this.cacheMode = CacheMode.NONE;
}
+ },
+
+ onEnable () {
+ this._super();
// Keep track of Node size
- this.node.on(cc.Node.EventType.SIZE_CHANGED, this._updateRenderData, this);
- this.node.on(cc.Node.EventType.ANCHOR_CHANGED, this._updateRenderData, this);
+ this.node.on(cc.Node.EventType.SIZE_CHANGED, this._nodeSizeChanged, this);
+ this.node.on(cc.Node.EventType.ANCHOR_CHANGED, this.setVertsDirty, this);
+ this.node.on(cc.Node.EventType.COLOR_CHANGED, this._nodeColorChanged, this);
- this._checkStringEmpty();
- this._updateAssembler();
- this._activateMaterial();
+ this._forceUpdateRenderData();
},
onDisable () {
this._super();
- this.node.off(cc.Node.EventType.SIZE_CHANGED, this._updateRenderData, this);
- this.node.off(cc.Node.EventType.ANCHOR_CHANGED, this._updateRenderData, this);
+ this.node.off(cc.Node.EventType.SIZE_CHANGED, this._nodeSizeChanged, this);
+ this.node.off(cc.Node.EventType.ANCHOR_CHANGED, this.setVertsDirty, this);
+ this.node.off(cc.Node.EventType.COLOR_CHANGED, this._nodeColorChanged, this);
},
onDestroy () {
- this._assembler._resetAssemblerData && this._assembler._resetAssemblerData(this._assemblerData);
+ this._assembler && this._assembler._resetAssemblerData && this._assembler._resetAssemblerData(this._assemblerData);
this._assemblerData = null;
+ this._letterTexture = null;
if (this._ttfTexture) {
this._ttfTexture.destroy();
this._ttfTexture = null;
@@ -487,132 +642,195 @@ let Label = cc.Class({
this._super();
},
- _canRender () {
- let result = this._super();
- let font = this.font;
- if (font instanceof cc.BitmapFont) {
- let spriteFrame = font.spriteFrame;
- // cannot be activated if texture not loaded yet
- if (!spriteFrame || !spriteFrame.textureLoaded()) {
- result = false;
- }
+ _nodeSizeChanged () {
+ // Because the content size is automatically updated when overflow is NONE.
+ // And this will conflict with the alignment of the CCWidget.
+ if (CC_EDITOR || this.overflow !== Overflow.NONE) {
+ this.setVertsDirty();
}
- return result;
},
- _checkStringEmpty () {
- this.markForRender(!!this.string);
+ _nodeColorChanged () {
+ if (!(this.font instanceof cc.BitmapFont)) {
+ this.setVertsDirty();
+ }
},
- _updateAssembler () {
- let assembler = Label._assembler.getAssembler(this);
-
- if (this._assembler !== assembler) {
- this._assembler = assembler;
- this._renderData = null;
+ setVertsDirty() {
+ if(CC_JSB && this._nativeTTF()) {
+ this._assembler && this._assembler.updateRenderData(this)
}
+ this._super();
+ },
- if (!this._renderData) {
- this._renderData = this._assembler.createData(this);
+ _updateColor () {
+ if (!(this.font instanceof cc.BitmapFont)) {
+ if (!(this._srcBlendFactor === cc.macro.BlendFactor.SRC_ALPHA && this.node._renderFlag & cc.RenderFlow.FLAG_OPACITY)) {
+ this.setVertsDirty();
+ }
}
+ RenderComponent.prototype._updateColor.call(this);
},
- _activateMaterial (force) {
- let material = this._material;
- if (material && !force) {
+ _validateRender () {
+ if (!this.string) {
+ this.disableRender();
return;
}
-
- let font = this.font;
- if (font instanceof cc.BitmapFont) {
- let spriteFrame = font.spriteFrame;
- // cannot be activated if texture not loaded yet
- if (!spriteFrame || !spriteFrame.textureLoaded()) {
- this.disableRender();
- if (spriteFrame) {
- spriteFrame.once('load', this._activateMaterial, this);
- spriteFrame.ensureLoadTexture();
+ if (this._materials[0]) {
+ let font = this.font;
+ if (font instanceof cc.BitmapFont) {
+ let spriteFrame = font.spriteFrame;
+ if (spriteFrame &&
+ spriteFrame.textureLoaded() &&
+ font._fntConfig) {
+ return;
}
- return;
}
-
- // TODO: old texture in material have been released by loader
- this._texture = spriteFrame._texture;
- }
- else {
- if (!this._ttfTexture) {
- this._ttfTexture = new cc.Texture2D();
- // TTF texture in web will blend with canvas or body background color
- if (!CC_JSB) {
- this._ttfTexture.setPremultiplyAlpha(true);
- }
- this._assemblerData = this._assembler._getAssemblerData();
- this._ttfTexture.initWithElement(this._assemblerData.canvas);
+ else {
+ return;
}
- this._texture = this._ttfTexture;
}
- // Canvas
- if (cc.game.renderType === cc.game.RENDER_TYPE_CANVAS) {
- this._texture.url = this.uuid + '_texture';
- }
- // WebGL
- else {
- if (!material) {
- material = new SpriteMaterial();
- }
- // Setup blend function for premultiplied ttf label texture
- if (this._texture === this._ttfTexture) {
- this._srcBlendFactor = cc.macro.BlendFactor.ONE;
- }
- else {
- this._srcBlendFactor = cc.macro.BlendFactor.SRC_ALPHA;
- }
- material.texture = this._texture;
- this._updateMaterial(material);
+ this.disableRender();
+ },
+
+ _resetAssembler () {
+ this._resetFrame();
+ RenderComponent.prototype._resetAssembler.call(this);
+ },
+
+ _resetFrame () {
+ if (this._frame) {
+ deleteFromDynamicAtlas(this, this._frame);
+ this._frame = null;
}
+ },
- this.markForUpdateRenderData(true);
+ _checkStringEmpty () {
+ this.markForRender(!!this.string);
+ },
+
+ _on3DNodeChanged () {
+ this._resetAssembler();
+ this._applyFontTexture();
+ },
+
+ _onBMFontTextureLoaded () {
+ this._frame._texture = this.font.spriteFrame._texture;
this.markForRender(true);
+ this._updateMaterial();
+ this._assembler && this._assembler.updateRenderData(this);
},
- _updateColor () {
+ _onBlendChanged () {
+ if (!this.useSystemFont || !this.enabledInHierarchy) return;
+
+ this._forceUpdateRenderData();
+ },
+
+ _applyFontTexture () {
let font = this.font;
if (font instanceof cc.BitmapFont) {
- this._super();
+ let spriteFrame = font.spriteFrame;
+ this._frame = spriteFrame;
+ if (spriteFrame) {
+ spriteFrame.onTextureLoaded(this._onBMFontTextureLoaded, this);
+ }
}
else {
- this._updateRenderData();
- this.node._renderFlag &= ~RenderFlow.FLAG_COLOR;
+ if(!this._nativeTTF()){
+ if (!this._frame) {
+ this._frame = new LabelFrame();
+ }
+
+ if (this.cacheMode === CacheMode.CHAR) {
+ this._letterTexture = this._assembler._getAssemblerData();
+ this._frame._refreshTexture(this._letterTexture);
+ } else if (!this._ttfTexture) {
+ this._ttfTexture = new cc.Texture2D();
+ this._assemblerData = this._assembler._getAssemblerData();
+ this._ttfTexture.initWithElement(this._assemblerData.canvas);
+ }
+
+ if (this.cacheMode !== CacheMode.CHAR) {
+ this._frame._resetDynamicAtlasFrame();
+ this._frame._refreshTexture(this._ttfTexture);
+ if (this._srcBlendFactor === cc.macro.BlendFactor.ONE && !CC_NATIVERENDERER) {
+ this._ttfTexture.setPremultiplyAlpha(true);
+ }
+ }
+ this._updateMaterial();
+ }
+ this._assembler && this._assembler.updateRenderData(this);
}
+ this.markForValidate();
},
- _updateRenderData (force) {
- let renderData = this._renderData;
- if (renderData) {
- renderData.vertDirty = true;
- renderData.uvDirty = true;
- this.markForUpdateRenderData(true);
- }
+ _updateMaterialCanvas () {
+ if (!this._frame) return;
+ this._frame._texture._nativeUrl = this.uuid + '_texture';
+ },
- if (CC_EDITOR || force) {
- this._updateAssembler();
- this._activateMaterial(force);
- this._assembler.updateRenderData(this);
+ _updateMaterialWebgl () {
+
+ let material = this.getMaterial(0);
+ if(this._nativeTTF()) {
+ if(material) this._assembler._updateTTFMaterial(this)
+ return;
}
+
+ if (!this._frame) return;
+ material && material.setProperty('texture', this._frame._texture);
+
+ BlendFunc.prototype._updateMaterial.call(this);
+ },
+
+ _forceUseCanvas: false,
+
+ _useNativeTTF() {
+ return cc.macro.ENABLE_NATIVE_TTF_RENDERER && !this._forceUseCanvas;
+ },
+
+ _nativeTTF() {
+ return this._useNativeTTF() && !!this._assembler && !!this._assembler._updateTTFMaterial;
},
+ _forceUpdateRenderData () {
+ this.setVertsDirty();
+ this._resetAssembler();
+ this._applyFontTexture();
+ },
+
+ /**
+ * @deprecated `label._enableBold` is deprecated, use `label.enableBold = true` instead please.
+ */
_enableBold (enabled) {
- this._isBold = !!enabled;
+ if (CC_DEBUG) {
+ cc.warn('`label._enableBold` is deprecated, use `label.enableBold = true` instead please');
+ }
+ this.enableBold = !!enabled;
},
+ /**
+ * @deprecated `label._enableItalics` is deprecated, use `label.enableItalics = true` instead please.
+ */
_enableItalics (enabled) {
- this._isItalic = !!enabled;
+ if (CC_DEBUG) {
+ cc.warn('`label._enableItalics` is deprecated, use `label.enableItalics = true` instead please');
+ }
+ this.enableItalic = !!enabled;
},
+ /**
+ * @deprecated `label._enableUnderline` is deprecated, use `label.enableUnderline = true` instead please.
+ */
_enableUnderline (enabled) {
- this._isUnderline = !!enabled;
+ if (CC_DEBUG) {
+ cc.warn('`label._enableUnderline` is deprecated, use `label.enableUnderline = true` instead please');
+ }
+ this.enableUnderline = !!enabled;
},
});
diff --git a/cocos2d/core/components/CCLabelOutline.js b/cocos2d/core/components/CCLabelOutline.js
index ae859c15458..a9593c830fc 100644
--- a/cocos2d/core/components/CCLabelOutline.js
+++ b/cocos2d/core/components/CCLabelOutline.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -25,7 +25,7 @@
****************************************************************************/
/**
- * !#en Outline effect used to change the display, only used for TTF font
+ * !#en Outline effect used to change the display, only for system fonts or TTF fonts
* !#zh 描边效果组件,用于字体描边,只能用于系统字体
* @class LabelOutline
* @extends Component
@@ -33,6 +33,7 @@
* // Create a new node and add label components.
* var node = new cc.Node("New Label");
* var label = node.addComponent(cc.Label);
+ * label.string = "hello world";
* var outline = node.addComponent(cc.LabelOutline);
* node.parent = this.node;
*/
@@ -47,23 +48,26 @@ let LabelOutline = cc.Class({
},
properties: {
- _color: cc.color(255,255,255,255),
+ _color: cc.Color.WHITE,
_width: 1,
/**
- * !#en Change the outline color
+ * !#en outline color
* !#zh 改变描边的颜色
* @property color
* @type {Color}
* @example
- * outline.color = new cc.Color(0.5, 0.3, 0.7, 1.0);;
+ * outline.color = cc.Color.BLACK;
*/
color: {
+ tooltip: CC_DEV && 'i18n:COMPONENT.outline.color',
get: function () {
- return this._color;
+ return this._color.clone();
},
set: function (value) {
- this._color = cc.color(value);
+ if (!this._color.equals(value)) {
+ this._color.set(value);
+ }
this._updateRenderData();
}
},
@@ -77,20 +81,32 @@ let LabelOutline = cc.Class({
* outline.width = 3;
*/
width: {
+ tooltip: CC_DEV && 'i18n:COMPONENT.outline.width',
get: function () {
return this._width;
},
set: function (value) {
+ if (this._width === value) return;
+
this._width = value;
this._updateRenderData();
- }
+ },
+ range: [0, 512],
}
},
+ onEnable () {
+ this._updateRenderData();
+ },
+
+ onDisable () {
+ this._updateRenderData();
+ },
+
_updateRenderData () {
let label = this.node.getComponent(cc.Label);
if (label) {
- label._updateRenderData(true);
+ label.setVertsDirty();
}
}
diff --git a/cocos2d/core/components/CCLabelShadow.js b/cocos2d/core/components/CCLabelShadow.js
new file mode 100644
index 00000000000..b1583cbca3c
--- /dev/null
+++ b/cocos2d/core/components/CCLabelShadow.js
@@ -0,0 +1,133 @@
+/****************************************************************************
+ Copyright (c) 2013-2016 Chukong Technologies Inc.
+ Copyright (c) 2017-2019 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+/**
+ * !#en Shadow effect for Label component, only for system fonts or TTF fonts
+ * !#zh 用于给 Label 组件添加阴影效果,只能用于系统字体或 ttf 字体
+ * @class LabelShadow
+ * @extends Component
+ * @example
+ * // Create a new node and add label components.
+ * var node = new cc.Node("New Label");
+ * var label = node.addComponent(cc.Label);
+ * label.string = "hello world";
+ * var labelShadow = node.addComponent(cc.LabelShadow);
+ * node.parent = this.node;
+ */
+
+let LabelShadow = cc.Class({
+ name: 'cc.LabelShadow',
+ extends: require('./CCComponent'),
+ editor: CC_EDITOR && {
+ menu: 'i18n:MAIN_MENU.component.renderers/LabelShadow',
+ executeInEditMode: true,
+ requireComponent: cc.Label,
+ },
+
+ properties: {
+ _color: cc.Color.WHITE,
+ _offset: cc.v2(2, 2),
+ _blur: 2,
+
+ /**
+ * !#en The shadow color
+ * !#zh 阴影的颜色
+ * @property color
+ * @type {Color}
+ * @example
+ * labelShadow.color = cc.Color.YELLOW;
+ */
+ color: {
+ tooltip: CC_DEV && 'i18n:COMPONENT.shadow.color',
+ get: function () {
+ return this._color.clone();
+ },
+ set: function (value) {
+ if (!this._color.equals(value)) {
+ this._color.set(value);
+ }
+ this._updateRenderData();
+ }
+ },
+
+ /**
+ * !#en Offset between font and shadow
+ * !#zh 字体与阴影的偏移
+ * @property offset
+ * @type {Vec2}
+ * @example
+ * labelShadow.offset = new cc.Vec2(2, 2);
+ */
+ offset: {
+ tooltip: CC_DEV && 'i18n:COMPONENT.shadow.offset',
+ get: function () {
+ return this._offset;
+ },
+ set: function (value) {
+ this._offset = value;
+ this._updateRenderData();
+ }
+ },
+
+ /**
+ * !#en A non-negative float specifying the level of shadow blur
+ * !#zh 阴影的模糊程度
+ * @property blur
+ * @type {Number}
+ * @example
+ * labelShadow.blur = 2;
+ */
+ blur: {
+ tooltip: CC_DEV && 'i18n:COMPONENT.shadow.blur',
+ get: function () {
+ return this._blur;
+ },
+ set: function (value) {
+ this._blur = value;
+ this._updateRenderData();
+ },
+ range: [0, 1024],
+ },
+ },
+
+ onEnable () {
+ this._updateRenderData();
+ },
+
+ onDisable () {
+ this._updateRenderData();
+ },
+
+ _updateRenderData () {
+ let label = this.node.getComponent(cc.Label);
+ if (label) {
+ label.markForRender(true);
+ }
+ }
+
+});
+
+cc.LabelShadow = module.exports = LabelShadow;
diff --git a/cocos2d/core/components/CCLayout.js b/cocos2d/core/components/CCLayout.js
index ad0c8b7ff94..d0dc0148095 100644
--- a/cocos2d/core/components/CCLayout.js
+++ b/cocos2d/core/components/CCLayout.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -281,9 +281,6 @@ var Layout = cc.Class({
animatable: false
},
- _N$padding: {
- default: 0
- },
/**
* !#en The left padding of layout, it only effect the layout in one direction.
* !#zh 容器内左边距,只会在一个布局方向上生效。
@@ -395,6 +392,23 @@ var Layout = cc.Class({
tooltip: CC_DEV && 'i18n:COMPONENT.layout.horizontal_direction',
animatable: false
},
+
+ /**
+ * !#en Adjust the layout if the children scaled.
+ * !#zh 子节点缩放比例是否影响布局。
+ * @property affectedByScale
+ * @type {Boolean}
+ * @default false
+ */
+ affectedByScale: {
+ default: false,
+ notify: function () {
+ // every time you switch this state, the layout will be calculated.
+ this._doLayoutDirty();
+ },
+ animatable: false,
+ tooltip: CC_DEV && 'i18n:COMPONENT.layout.affected_by_scale'
+ }
},
statics: {
@@ -405,14 +419,6 @@ var Layout = cc.Class({
AxisDirection: AxisDirection,
},
- _migratePaddingData: function () {
- this.paddingLeft = this._N$padding;
- this.paddingRight = this._N$padding;
- this.paddingTop = this._N$padding;
- this.paddingBottom = this._N$padding;
- this._N$padding = 0;
- },
-
onEnable: function () {
this._addEventListeners();
@@ -420,10 +426,6 @@ var Layout = cc.Class({
this.node.setContentSize(this._layoutSize);
}
- if (this._N$padding !== 0) {
- this._migratePaddingData();
- }
-
this._doLayoutDirty();
},
@@ -435,6 +437,10 @@ var Layout = cc.Class({
this._layoutDirty = true;
},
+ _doScaleDirty: function () {
+ this._layoutDirty = this._layoutDirty || this.affectedByScale;
+ },
+
_addEventListeners: function () {
cc.director.on(cc.Director.EVENT_AFTER_UPDATE, this.updateLayout, this);
this.node.on(NodeEvent.SIZE_CHANGED, this._resized, this);
@@ -459,6 +465,7 @@ var Layout = cc.Class({
var children = this.node.children;
for (var i = 0; i < children.length; ++i) {
var child = children[i];
+ child.on(NodeEvent.SCALE_CHANGED, this._doScaleDirty, this);
child.on(NodeEvent.SIZE_CHANGED, this._doLayoutDirty, this);
child.on(NodeEvent.POSITION_CHANGED, this._doLayoutDirty, this);
child.on(NodeEvent.ANCHOR_CHANGED, this._doLayoutDirty, this);
@@ -470,6 +477,7 @@ var Layout = cc.Class({
var children = this.node.children;
for (var i = 0; i < children.length; ++i) {
var child = children[i];
+ child.off(NodeEvent.SCALE_CHANGED, this._doScaleDirty, this);
child.off(NodeEvent.SIZE_CHANGED, this._doLayoutDirty, this);
child.off(NodeEvent.POSITION_CHANGED, this._doLayoutDirty, this);
child.off(NodeEvent.ANCHOR_CHANGED, this._doLayoutDirty, this);
@@ -478,6 +486,7 @@ var Layout = cc.Class({
},
_childAdded: function (child) {
+ child.on(NodeEvent.SCALE_CHANGED, this._doScaleDirty, this);
child.on(NodeEvent.SIZE_CHANGED, this._doLayoutDirty, this);
child.on(NodeEvent.POSITION_CHANGED, this._doLayoutDirty, this);
child.on(NodeEvent.ANCHOR_CHANGED, this._doLayoutDirty, this);
@@ -487,6 +496,7 @@ var Layout = cc.Class({
},
_childRemoved: function (child) {
+ child.off(NodeEvent.SCALE_CHANGED, this._doScaleDirty, this);
child.off(NodeEvent.SIZE_CHANGED, this._doLayoutDirty, this);
child.off(NodeEvent.POSITION_CHANGED, this._doLayoutDirty, this);
child.off(NodeEvent.ANCHOR_CHANGED, this._doLayoutDirty, this);
@@ -537,8 +547,8 @@ var Layout = cc.Class({
for (var i = 0; i < children.length; ++i) {
var child = children[i];
- let childScaleX = Math.abs(child.scaleX);
- let childScaleY = Math.abs(child.scaleY);
+ let childScaleX = this._getUsedScaleValue(child.scaleX);
+ let childScaleY = this._getUsedScaleValue(child.scaleY);
if (!child.activeInHierarchy) {
continue;
}
@@ -635,7 +645,7 @@ var Layout = cc.Class({
var child = children[i];
if (child.activeInHierarchy) {
activeChildCount++;
- newHeight += child.height * Math.abs(child.scaleY);
+ newHeight += child.height * this._getUsedScaleValue(child.scaleY);
}
}
@@ -683,8 +693,8 @@ var Layout = cc.Class({
for (var i = 0; i < children.length; ++i) {
var child = children[i];
- let childScaleX = Math.abs(child.scaleX);
- let childScaleY = Math.abs(child.scaleY);
+ let childScaleX = this._getUsedScaleValue(child.scaleX);
+ let childScaleY = this._getUsedScaleValue(child.scaleY);
if (!child.activeInHierarchy) {
continue;
}
@@ -792,22 +802,25 @@ var Layout = cc.Class({
}
if (allChildrenBoundingBox) {
- var leftBottomInParentSpace = this.node.parent.convertToNodeSpaceAR(cc.v2(allChildrenBoundingBox.x, allChildrenBoundingBox.y));
- leftBottomInParentSpace = cc.v2(leftBottomInParentSpace.x - this.paddingLeft, leftBottomInParentSpace.y - this.paddingBottom);
+ var leftBottomSpace = this.node.convertToNodeSpaceAR(cc.v2(allChildrenBoundingBox.x, allChildrenBoundingBox.y));
+ leftBottomSpace = cc.v2(leftBottomSpace.x - this.paddingLeft, leftBottomSpace.y - this.paddingBottom);
- var rightTopInParentSpace = this.node.parent.convertToNodeSpaceAR(cc.v2(allChildrenBoundingBox.x + allChildrenBoundingBox.width,
- allChildrenBoundingBox.y + allChildrenBoundingBox.height));
- rightTopInParentSpace = cc.v2(rightTopInParentSpace.x + this.paddingRight, rightTopInParentSpace.y + this.paddingTop);
+ var rightTopSpace = this.node.convertToNodeSpaceAR(cc.v2(allChildrenBoundingBox.xMax, allChildrenBoundingBox.yMax));
+ rightTopSpace = cc.v2(rightTopSpace.x + this.paddingRight, rightTopSpace.y + this.paddingTop);
- var newSize = cc.size(parseFloat((rightTopInParentSpace.x - leftBottomInParentSpace.x).toFixed(2)),
- parseFloat((rightTopInParentSpace.y - leftBottomInParentSpace.y).toFixed(2)));
+ var newSize = rightTopSpace.sub(leftBottomSpace);
+ newSize = cc.size(parseFloat(newSize.x.toFixed(2)), parseFloat(newSize.y.toFixed(2)));
- var layoutPosition = this.node.getPosition();
- var newAnchorX = (layoutPosition.x - leftBottomInParentSpace.x) / newSize.width;
- var newAnchorY = (layoutPosition.y - leftBottomInParentSpace.y) / newSize.height;
- var newAnchor = cc.v2(parseFloat(newAnchorX.toFixed(2)), parseFloat(newAnchorY.toFixed(2)));
-
- this.node.setAnchorPoint(newAnchor);
+ if (newSize.width !== 0) {
+ // Invert is to get the coordinate point of the child node in the parent coordinate system
+ var newAnchorX = (-leftBottomSpace.x) / newSize.width;
+ this.node.anchorX = parseFloat(newAnchorX.toFixed(2));
+ }
+ if (newSize.height !== 0) {
+ // Invert is to get the coordinate point of the child node in the parent coordinate system
+ var newAnchorY = (-leftBottomSpace.y) / newSize.height;
+ this.node.anchorY = parseFloat(newAnchorY.toFixed(2));
+ }
this.node.setContentSize(newSize);
}
},
@@ -825,7 +838,7 @@ var Layout = cc.Class({
}
var fnPositionY = function (child, topOffset, row) {
- return bottomBoundaryOfLayout + sign * (topOffset + child.anchorY * child.height * Math.abs(child.scaleY) + paddingY + row * this.spacingY);
+ return bottomBoundaryOfLayout + sign * (topOffset + child.anchorY * child.height * this._getUsedScaleValue(child.scaleY) + paddingY + row * this.spacingY);
}.bind(this);
@@ -866,7 +879,7 @@ var Layout = cc.Class({
}
var fnPositionX = function (child, leftOffset, column) {
- return leftBoundaryOfLayout + sign * (leftOffset + child.anchorX * child.width * Math.abs(child.scaleX) + paddingX + column * this.spacingX);
+ return leftBoundaryOfLayout + sign * (leftOffset + child.anchorX * child.width * this._getUsedScaleValue(child.scaleX) + paddingX + column * this.spacingX);
}.bind(this);
var newWidth = 0;
@@ -914,7 +927,7 @@ var Layout = cc.Class({
var child = children[i];
if (child.activeInHierarchy) {
activeChildCount++;
- newWidth += child.width * Math.abs(child.scaleX);
+ newWidth += child.width * this._getUsedScaleValue(child.scaleX);
}
}
newWidth += (activeChildCount - 1) * this.spacingX + this.paddingLeft + this.paddingRight;
@@ -959,6 +972,10 @@ var Layout = cc.Class({
}
},
+ _getUsedScaleValue (value) {
+ return this.affectedByScale ? Math.abs(value) : 1;
+ },
+
/**
* !#en Perform the layout update
* !#zh 立即执行更新布局
@@ -978,25 +995,6 @@ var Layout = cc.Class({
this._layoutDirty = false;
}
}
-
-});
-
-/**
- * !#en The padding of layout, it effects the layout in four direction.
- * !#zh 容器内边距,该属性会在四个布局方向上生效。
- * @property {Number} padding
- */
-Object.defineProperty(Layout.prototype, "padding", {
- get: function () {
- cc.warnID(4100);
- return this.paddingLeft;
- },
- set: function (value) {
- this._N$padding = value;
-
- this._migratePaddingData();
- this._doLayoutDirty();
- }
});
cc.Layout = module.exports = Layout;
diff --git a/cocos2d/core/components/CCMask.js b/cocos2d/core/components/CCMask.js
index 35f58a94f5b..da08d26ba87 100644
--- a/cocos2d/core/components/CCMask.js
+++ b/cocos2d/core/components/CCMask.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -24,16 +24,31 @@
THE SOFTWARE.
****************************************************************************/
+import gfx from '../../renderer/gfx';
+
const misc = require('../utils/misc');
-const renderEngine = require('../renderer/render-engine');
-const math = renderEngine.math;
-const StencilMaterial = renderEngine.StencilMaterial;
const RenderComponent = require('./CCRenderComponent');
const RenderFlow = require('../renderer/render-flow');
const Graphics = require('../graphics/graphics');
-let _vec2_temp = cc.v2();
-let _mat4_temp = math.mat4.create();
+import Mat4 from '../value-types/mat4';
+import Vec2 from '../value-types/vec2';
+import MaterialVariant from '../assets/material/material-variant';
+
+let _vec2_temp = new Vec2();
+let _mat4_temp = new Mat4();
+
+let _circlepoints =[];
+function _calculateCircle (center, radius, segements) {
+ _circlepoints.length = 0;
+ let anglePerStep = Math.PI * 2 / segements;
+ for (let step = 0; step < segements; ++step) {
+ _circlepoints.push(cc.v2(radius.x * Math.cos(anglePerStep * step) + center.x,
+ radius.y * Math.sin(anglePerStep * step) + center.y));
+ }
+
+ return _circlepoints;
+}
/**
* !#en the type for mask.
@@ -68,7 +83,7 @@ const SEGEMENTS_MAX = 10000;
* !#en The Mask Component
* !#zh 遮罩组件
* @class Mask
- * @extends Component
+ * @extends RenderComponent
*/
let Mask = cc.Class({
name: 'cc.Mask',
@@ -80,6 +95,14 @@ let Mask = cc.Class({
inspector: 'packages://inspector/inspectors/comps/mask.js'
},
+ ctor () {
+ this._graphics = null;
+
+ this._enableMaterial = null;
+ this._exitMaterial = null;
+ this._clearMaterial = null;
+ },
+
properties: {
_spriteFrame: {
default: null,
@@ -100,16 +123,17 @@ let Mask = cc.Class({
return this._type;
},
set: function (value) {
+ if (this._type !== value) {
+ this._resetAssembler();
+ }
+
this._type = value;
if (this._type !== MaskType.IMAGE_STENCIL) {
this.spriteFrame = null;
this.alphaThreshold = 0;
this._updateGraphics();
}
- if (this._renderData) {
- this.destroyRenderData(this._renderData);
- this._renderData = null;
- }
+
this._activateMaterial();
},
type: MaskType,
@@ -144,7 +168,9 @@ let Mask = cc.Class({
}
}
this._spriteFrame = value;
- this._applySpriteFrame(lastSprite);
+
+ this.setVertsDirty();
+ this._updateMaterial();
},
},
@@ -153,20 +179,19 @@ let Mask = cc.Class({
* The alpha threshold.(Not supported Canvas Mode)
* The content is drawn only where the stencil have pixel with alpha greater than the alphaThreshold.
* Should be a float between 0 and 1.
- * This default to 0 (so alpha test is disabled).
- * When it's set to 1, the stencil will discard all pixels, nothing will be shown,
- * In previous version, it act as if the alpha test is disabled, which is incorrect.
+ * This default to 0.1.
+ * When it's set to 1, the stencil will discard all pixels, nothing will be shown.
* !#zh
* Alpha 阈值(不支持 Canvas 模式)
- * 只有当模板的像素的 alpha 大于 alphaThreshold 时,才会绘制内容。
- * 该数值 0 ~ 1 之间的浮点数,默认值为 0(因此禁用 alpha 测试)
- * 当被设置为 1 时,会丢弃所有蒙版像素,所以不会显示任何内容,在之前的版本中,设置为 1 等同于 0,这种效果其实是不正确的
+ * 只有当模板的像素的 alpha 大于等于 alphaThreshold 时,才会绘制内容。
+ * 该数值 0 ~ 1 之间的浮点数,默认值为 0.1
+ * 当被设置为 1 时,会丢弃所有蒙版像素,所以不会显示任何内容
* @property alphaThreshold
* @type {Number}
- * @default 0
+ * @default 0.1
*/
alphaThreshold: {
- default: 0,
+ default: 0.1,
type: cc.Float,
range: [0, 1, 0.1],
slide: true,
@@ -176,10 +201,7 @@ let Mask = cc.Class({
cc.warnID(4201);
return;
}
- if (this._material) {
- this._material.alphaThreshold = this.alphaThreshold;
- this._material.updateHash();
- }
+ this._updateMaterial();
}
},
@@ -197,7 +219,6 @@ let Mask = cc.Class({
notify: function () {
if (cc.game.renderType === cc.game.RENDER_TYPE_CANVAS) {
cc.warnID(4202);
- return;
}
}
},
@@ -217,7 +238,9 @@ let Mask = cc.Class({
},
set: function (value) {
this._segments = misc.clampf(value, SEGEMENTS_MIN, SEGEMENTS_MAX);
+ this._updateGraphics();
},
+ type: cc.Integer,
tooltip: CC_DEV && 'i18n:COMPONENT.mask.segements',
},
@@ -235,37 +258,13 @@ let Mask = cc.Class({
Type: MaskType,
},
- onLoad () {
- this._graphics = new Graphics();
- this._graphics.node = this.node;
- this._graphics.lineWidth = 0;
- this._graphics.strokeColor = cc.color(0, 0, 0, 0);
- },
-
onRestore () {
- if (!this._graphics) {
- this._graphics = new Graphics();
- this._graphics.node = this.node;
- this._graphics.lineWidth = 0;
- }
- if (this._type !== MaskType.IMAGE_STENCIL) {
- this._updateGraphics();
- }
+ this._activateMaterial();
},
onEnable () {
this._super();
- if (this._type === MaskType.IMAGE_STENCIL) {
- if (!this._spriteFrame || !this._spriteFrame.textureLoaded()) {
- // Do not render when sprite frame is not ready
- this.markForRender(false);
- if (this._spriteFrame) {
- this._spriteFrame.once('load', this._onTextureLoaded, this);
- this._spriteFrame.ensureLoadTexture();
- }
- }
- }
- else {
+ if (this._type !== MaskType.IMAGE_STENCIL) {
this._updateGraphics();
}
@@ -274,9 +273,6 @@ let Mask = cc.Class({
this.node.on(cc.Node.EventType.SCALE_CHANGED, this._updateGraphics, this);
this.node.on(cc.Node.EventType.SIZE_CHANGED, this._updateGraphics, this);
this.node.on(cc.Node.EventType.ANCHOR_CHANGED, this._updateGraphics, this);
-
- this.node._renderFlag |= RenderFlow.FLAG_POST_RENDER;
- this._activateMaterial();
},
onDisable () {
@@ -287,13 +283,13 @@ let Mask = cc.Class({
this.node.off(cc.Node.EventType.SCALE_CHANGED, this._updateGraphics, this);
this.node.off(cc.Node.EventType.SIZE_CHANGED, this._updateGraphics, this);
this.node.off(cc.Node.EventType.ANCHOR_CHANGED, this._updateGraphics, this);
-
+
this.node._renderFlag &= ~RenderFlow.FLAG_POST_RENDER;
},
onDestroy () {
this._super();
- this._graphics.destroy();
+ this._removeGraphics();
},
_resizeNodeToTargetNode: CC_EDITOR && function () {
@@ -303,66 +299,81 @@ let Mask = cc.Class({
}
},
- _onTextureLoaded () {
- // Mark render data dirty
- if (this._renderData) {
- this._renderData.uvDirty = true;
- this._renderData.vertDirty = true;
- this.markForUpdateRenderData(true);
- }
- // Reactivate material
- if (this.enabledInHierarchy) {
- this._activateMaterial();
- }
- },
+ _validateRender () {
+ if (this._type !== MaskType.IMAGE_STENCIL) return;
- _applySpriteFrame (oldFrame) {
- if (oldFrame && oldFrame.off) {
- oldFrame.off('load', this._onTextureLoaded, this);
- }
let spriteFrame = this._spriteFrame;
- if (spriteFrame) {
- if (spriteFrame.textureLoaded()) {
- this._onTextureLoaded(null);
- }
- else {
- spriteFrame.once('load', this._onTextureLoaded, this);
- spriteFrame.ensureLoadTexture();
- }
+ if (spriteFrame &&
+ spriteFrame.textureLoaded()) {
+ return;
}
+
+ this.disableRender();
},
_activateMaterial () {
- // cannot be activated if texture not loaded yet
- if (this._type === MaskType.IMAGE_STENCIL && (!this.spriteFrame || !this.spriteFrame.textureLoaded())) {
- this.markForRender(false);
- return;
+ this._createGraphics();
+
+ // Init material
+ let material = this._materials[0];
+ if (!material) {
+ material = MaterialVariant.createWithBuiltin('2d-sprite', this);
+ }
+ else {
+ material = MaterialVariant.create(material, this);
}
- // WebGL
- if (cc.game.renderType !== cc.game.RENDER_TYPE_CANVAS) {
- // Init material
- if (!this._material) {
- this._material = new StencilMaterial();
- }
+ material.define('USE_ALPHA_TEST', true);
- // Reset material
- if (this._type === MaskType.IMAGE_STENCIL) {
- let texture = this.spriteFrame.getTexture();
- this._material.useModel = false;
- this._material.useTexture = true;
- this._material.useColor = true;
- this._material.texture = texture;
- this._material.alphaThreshold = this.alphaThreshold;
- }
- else {
- this._material.useModel = true;
- this._material.useTexture = false;
- this._material.useColor = false;
- }
+ // Reset material
+ if (this._type === MaskType.IMAGE_STENCIL) {
+ material.define('CC_USE_MODEL', false);
+ material.define('USE_TEXTURE', true);
+ }
+ else {
+ material.define('CC_USE_MODEL', true);
+ material.define('USE_TEXTURE', false);
+ }
+
+ if (!this._enableMaterial) {
+ this._enableMaterial = MaterialVariant.createWithBuiltin('2d-sprite', this);
+ }
+
+ if (!this._exitMaterial) {
+ this._exitMaterial = MaterialVariant.createWithBuiltin('2d-sprite', this);
+ this._exitMaterial.setStencilEnabled(gfx.STENCIL_DISABLE);
+ }
+
+ if (!this._clearMaterial) {
+ this._clearMaterial = MaterialVariant.createWithBuiltin('clear-stencil', this);
+ }
+
+ this.setMaterial(0, material);
+
+ this._graphics._materials[0] = material;
+
+ this._updateMaterial();
+ },
+
+ _updateMaterial () {
+ let material = this._materials[0];
+ if (!material) return;
+
+ if (this._type === MaskType.IMAGE_STENCIL && this.spriteFrame) {
+ let texture = this.spriteFrame.getTexture();
+ material.setProperty('texture', texture);
}
+ material.setProperty('alphaThreshold', this.alphaThreshold);
+ },
- this.markForRender(true);
+ _createGraphics () {
+ if (!this._graphics) {
+ this._graphics = new Graphics();
+ cc.Assembler.init(this._graphics);
+ this._graphics.node = this.node;
+ this._graphics.lineWidth = 0;
+ this._graphics.strokeColor = cc.color(0, 0, 0, 0);
+ }
},
_updateGraphics () {
@@ -378,11 +389,22 @@ let Mask = cc.Class({
graphics.rect(x, y, width, height);
}
else if (this._type === MaskType.ELLIPSE) {
- let cx = x + width / 2,
- cy = y + height / 2,
- rx = width / 2,
- ry = height / 2;
- graphics.ellipse(cx, cy, rx, ry);
+ let center = cc.v2(x + width / 2, y + height / 2);
+ let radius = {
+ x: width / 2,
+ y: height / 2
+ };
+ let points = _calculateCircle(center, radius, this._segments);
+ for (let i = 0; i < points.length; ++i) {
+ let point = points[i];
+ if (i === 0) {
+ graphics.moveTo(point.x, point.y);
+ }
+ else {
+ graphics.lineTo(point.x, point.y);
+ }
+ }
+ graphics.close();
}
if (cc.game.renderType === cc.game.RENDER_TYPE_CANVAS) {
graphics.stroke();
@@ -392,6 +414,14 @@ let Mask = cc.Class({
}
},
+ _removeGraphics () {
+ if (this._graphics) {
+ this._graphics.destroy();
+ this._graphics._destroyImmediate(); // FIX: cocos-creator/2d-tasks#2511. TODO: cocos-creator/2d-tasks#2516
+ this._graphics = null;
+ }
+ },
+
_hitTest (cameraPt) {
let node = this.node;
let size = node.getContentSize(),
@@ -400,37 +430,37 @@ let Mask = cc.Class({
testPt = _vec2_temp;
node._updateWorldMatrix();
- math.mat4.invert(_mat4_temp, node._worldMatrix);
- math.vec2.transformMat4(testPt, cameraPt, _mat4_temp);
+ // If scale is 0, it can't be hit.
+ if (!Mat4.invert(_mat4_temp, node._worldMatrix)) {
+ return false;
+ }
+ Vec2.transformMat4(testPt, cameraPt, _mat4_temp);
testPt.x += node._anchorPoint.x * w;
testPt.y += node._anchorPoint.y * h;
+ let result = false;
if (this.type === MaskType.RECT || this.type === MaskType.IMAGE_STENCIL) {
- return testPt.x >= 0 && testPt.y >= 0 && testPt.x <= w && testPt.y <= h;
+ result = testPt.x >= 0 && testPt.y >= 0 && testPt.x <= w && testPt.y <= h;
}
else if (this.type === MaskType.ELLIPSE) {
let rx = w / 2, ry = h / 2;
let px = testPt.x - 0.5 * w, py = testPt.y - 0.5 * h;
- return px * px / (rx * rx) + py * py / (ry * ry) < 1;
+ result = px * px / (rx * rx) + py * py / (ry * ry) < 1;
}
- },
-
- markForUpdateRenderData (enable) {
- if (enable && this.enabledInHierarchy) {
- this.node._renderFlag |= RenderFlow.FLAG_UPDATE_RENDER_DATA;
- }
- else if (!enable) {
- this.node._renderFlag &= ~RenderFlow.FLAG_UPDATE_RENDER_DATA;
+ if (this.inverted) {
+ result = !result;
}
+ return result;
},
markForRender (enable) {
- if (enable && this.enabledInHierarchy) {
- this.node._renderFlag |= (RenderFlow.FLAG_RENDER | RenderFlow.FLAG_UPDATE_RENDER_DATA |
- RenderFlow.FLAG_POST_RENDER);
+ let flag = RenderFlow.FLAG_RENDER | RenderFlow.FLAG_UPDATE_RENDER_DATA | RenderFlow.FLAG_POST_RENDER;
+ if (enable) {
+ this.node._renderFlag |= flag;
+ this.markForValidate();
}
else if (!enable) {
- this.node._renderFlag &= ~(RenderFlow.FLAG_RENDER | RenderFlow.FLAG_POST_RENDER);
+ this.node._renderFlag &= ~flag;
}
},
diff --git a/cocos2d/core/components/CCMotionStreak.js b/cocos2d/core/components/CCMotionStreak.js
index 2db3ef1e9b9..0b24abfe2f3 100644
--- a/cocos2d/core/components/CCMotionStreak.js
+++ b/cocos2d/core/components/CCMotionStreak.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -25,8 +25,7 @@
****************************************************************************/
const RenderComponent = require('../components/CCRenderComponent');
-const SpriteMaterial = require('../renderer/render-engine').SpriteMaterial;
-const textureUtil = require('../utils/texture-util');
+const BlendFunc = require('../../core/utils/blend-func');
/**
* !#en
@@ -40,6 +39,7 @@ const textureUtil = require('../utils/texture-util');
* !#zh 运动轨迹,用于游戏对象的运动轨迹上实现拖尾渐隐效果。
* @class MotionStreak
* @extends Component
+ * @uses BlendFunc
*/
var MotionStreak = cc.Class({
name: 'cc.MotionStreak',
@@ -50,6 +50,7 @@ var MotionStreak = cc.Class({
// 2.Need to update the position in each frame by itself because we don't know
// whether the global position have changed
extends: RenderComponent,
+ mixins: [BlendFunc],
editor: CC_EDITOR && {
menu: 'i18n:MAIN_MENU.component.others/MotionStreak',
@@ -159,14 +160,7 @@ var MotionStreak = cc.Class({
if (this._texture === value) return;
this._texture = value;
-
- if (!value || !value.loaded) {
- this.disableRender();
- this._ensureLoadTexture();
- }
- else {
- this._activateMaterial();
- }
+ this._updateMaterial();
},
type: cc.Texture2D,
animatable: false,
@@ -185,10 +179,12 @@ var MotionStreak = cc.Class({
_color: cc.Color.WHITE,
color: {
get () {
- return this._color;
+ return this._color.clone();
},
set (value) {
- this._color = value;
+ if (!this._color.equals(value)) {
+ this._color.set(value);
+ }
},
type: cc.Color,
tooltip: CC_DEV && 'i18n:COMPONENT.motionStreak.color'
@@ -218,40 +214,14 @@ var MotionStreak = cc.Class({
onEnable () {
this._super();
-
- if (!this._texture || !this._texture.loaded) {
- this.disableRender();
- this._ensureLoadTexture();
- }
- else {
- this._activateMaterial();
- }
this.reset();
},
- _ensureLoadTexture: function () {
- if (this._texture && !this._texture.loaded) {
- // load exists texture
- let self = this;
- textureUtil.postLoadTexture(this._texture, function () {
- self._activateMaterial();
- });
- }
- },
+ _updateMaterial () {
+ let material = this.getMaterial(0);
+ material && material.setProperty('texture', this._texture);
- _activateMaterial () {
- let material = this._material;
- if (!material) {
- material = this._material = new SpriteMaterial();
- material.useColor = false;
- }
-
- if (this._texture && this._texture.loaded) {
- material.texture = this._texture;
- this._updateMaterial(material);
- this.markForRender(true);
- this.markForUpdateRenderData(true);
- }
+ BlendFunc.prototype._updateMaterial.call(this);
},
onFocusInEditor: CC_EDITOR && function () {
@@ -276,16 +246,15 @@ var MotionStreak = cc.Class({
*/
reset () {
this._points.length = 0;
- let renderData = this._renderData;
- if (renderData) {
- renderData.dataLength = 0;
- renderData.vertexCount = 0;
- renderData.indiceCount = 0;
- }
+ this._assembler && this._assembler._renderData.clear();
if (CC_EDITOR) {
cc.engine.repaintInEditMode();
}
+ },
+
+ lateUpdate (dt) {
+ this._assembler && this._assembler.update(this, dt);
}
});
-cc.MotionStreak = module.exports = MotionStreak;
\ No newline at end of file
+cc.MotionStreak = module.exports = MotionStreak;
diff --git a/cocos2d/core/components/CCPageView.js b/cocos2d/core/components/CCPageView.js
index 7ef276a27c8..a3d22731b58 100644
--- a/cocos2d/core/components/CCPageView.js
+++ b/cocos2d/core/components/CCPageView.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -100,6 +100,7 @@ var PageView = cc.Class({
this._curPageIdx = 0;
this._lastPageIdx = 0;
this._pages = [];
+ this._initContentPos = cc.v2();
this._scrollCenterOffsetX = []; // 每一个页面居中时需要的偏移量(X)
this._scrollCenterOffsetY = []; // 每一个页面居中时需要的偏移量(Y)
},
@@ -223,12 +224,9 @@ var PageView = cc.Class({
EventType: EventType
},
- __preload: function () {
- this.node.on(cc.Node.EventType.SIZE_CHANGED, this._updateAllPagesSize, this);
- },
-
onEnable: function () {
this._super();
+ this.node.on(cc.Node.EventType.SIZE_CHANGED, this._updateAllPagesSize, this);
if(!CC_EDITOR) {
this.node.on('scroll-ended-with-threshold', this._dispatchPageTurningEvent, this);
}
@@ -236,6 +234,7 @@ var PageView = cc.Class({
onDisable: function () {
this._super();
+ this.node.off(cc.Node.EventType.SIZE_CHANGED, this._updateAllPagesSize, this);
if(!CC_EDITOR) {
this.node.off('scroll-ended-with-threshold', this._dispatchPageTurningEvent, this);
}
@@ -248,10 +247,6 @@ var PageView = cc.Class({
}
},
- onDestroy: function() {
- this.node.off(cc.Node.EventType.SIZE_CHANGED, this._updateAllPagesSize, this);
- },
-
/**
* !#en Returns current page index
* !#zh 返回当前页面索引
@@ -394,20 +389,15 @@ var PageView = cc.Class({
if (!this.content) { return; }
var layout = this.content.getComponent(cc.Layout);
if (layout) {
- if (this._pages.length === 0) {
- layout.padding = 0;
- }
- else {
+ if (this.sizeMode === SizeMode.Free && this._pages.length > 0) {
var lastPage = this._pages[this._pages.length - 1];
- if (this.sizeMode === SizeMode.Free) {
- if (this.direction === Direction.Horizontal) {
- layout.paddingLeft = (this.node.width - this._pages[0].width) / 2;
- layout.paddingRight = (this.node.width - lastPage.width) / 2;
- }
- else if (this.direction === Direction.Vertical) {
- layout.paddingTop = (this.node.height - this._pages[0].height) / 2;
- layout.paddingBottom = (this.node.height - lastPage.height) / 2;
- }
+ if (this.direction === Direction.Horizontal) {
+ layout.paddingLeft = (this._view.width - this._pages[0].width) / 2;
+ layout.paddingRight = (this._view.width - lastPage.width) / 2;
+ }
+ else if (this.direction === Direction.Vertical) {
+ layout.paddingTop = (this._view.height - this._pages[0].height) / 2;
+ layout.paddingBottom = (this._view.height - lastPage.height) / 2;
}
}
layout.updateLayout();
@@ -416,6 +406,12 @@ var PageView = cc.Class({
// 刷新页面视图
_updatePageView: function () {
+ // 当页面数组变化时修改 content 大小
+ var layout = this.content.getComponent(cc.Layout);
+ if (layout && layout.enabled) {
+ layout.updateLayout();
+ }
+
var pageCount = this._pages.length;
if (this._curPageIdx >= pageCount) {
@@ -423,22 +419,18 @@ var PageView = cc.Class({
this._lastPageIdx = this._curPageIdx;
}
// 进行排序
+ var contentPos = this._initContentPos;
for (var i = 0; i < pageCount; ++i) {
- this._pages[i].setSiblingIndex(i);
+ var page = this._pages[i];
+ page.setSiblingIndex(i);
if (this.direction === Direction.Horizontal) {
- this._scrollCenterOffsetX[i] = Math.abs(this.content.x + this._pages[i].x);
+ this._scrollCenterOffsetX[i] = Math.abs(contentPos.x + page.x);
}
else {
- this._scrollCenterOffsetY[i] = Math.abs(this.content.y + this._pages[i].y);
+ this._scrollCenterOffsetY[i] = Math.abs(contentPos.y + page.y);
}
}
- // 当页面数组变化时修改 content 大小
- var layout = this.content.getComponent(cc.Layout);
- if (layout && layout.enabled) {
- layout.updateLayout();
- }
-
// 刷新 indicator 信息与状态
if (this.indicator) {
this.indicator._refresh();
@@ -447,11 +439,11 @@ var PageView = cc.Class({
// 刷新所有页面的大小
_updateAllPagesSize: function () {
- if (this.sizeMode !== SizeMode.Unified) {
+ if (this.sizeMode !== SizeMode.Unified || !this._view) {
return;
}
var locPages = CC_EDITOR ? this.content.children : this._pages;
- var selfSize = this.node.getContentSize();
+ var selfSize = this._view.getContentSize();
for (var i = 0, len = locPages.length; i < len; i++) {
locPages[i].setContentSize(selfSize);
}
@@ -460,6 +452,7 @@ var PageView = cc.Class({
// 初始化页面
_initPages: function () {
if (!this.content) { return; }
+ this._initContentPos = this.content.position;
var children = this.content.children;
for (var i = 0; i < children.length; ++i) {
var page = children[i];
@@ -495,10 +488,10 @@ var PageView = cc.Class({
}
else {
if (this.direction === Direction.Horizontal) {
- return Math.abs(offset.x) >= this.node.width * this.scrollThreshold;
+ return Math.abs(offset.x) >= this._view.width * this.scrollThreshold;
}
else if (this.direction === Direction.Vertical) {
- return Math.abs(offset.y) >= this.node.height * this.scrollThreshold;
+ return Math.abs(offset.y) >= this._view.height * this.scrollThreshold;
}
}
},
@@ -531,10 +524,10 @@ var PageView = cc.Class({
}
else {
if (this.direction === Direction.Horizontal) {
- offset.x = idx * this.node.width;
+ offset.x = idx * this._view.width;
}
else if (this.direction === Direction.Vertical) {
- offset.y = idx * this.node.height;
+ offset.y = idx * this._view.height;
}
}
return offset;
@@ -553,24 +546,33 @@ var PageView = cc.Class({
},
_handleReleaseLogic: function(touch) {
+ this._autoScrollToPage();
+ if (this._scrolling) {
+ this._scrolling = false;
+ if (!this._autoScrolling) {
+ this._dispatchEvent('scroll-ended');
+ }
+ }
+ },
+
+ _autoScrollToPage: function () {
var bounceBackStarted = this._startBounceBackIfNeeded();
- var moveOffset = this._touchBeganPosition.sub(this._touchEndPosition);
if (bounceBackStarted) {
- var dragDirection = this._getDragDirection(moveOffset);
- if (dragDirection === 0) {
- return;
+ let bounceBackAmount = this._getHowMuchOutOfBoundary();
+ bounceBackAmount = this._clampDelta(bounceBackAmount);
+ if (bounceBackAmount.x > 0 || bounceBackAmount.y < 0) {
+ this._curPageIdx = this._pages.length === 0 ? 0 : this._pages.length - 1;
}
- if (dragDirection > 0) {
- this._curPageIdx = this._pages.length - 1;
- }
- else {
+ if (bounceBackAmount.x < 0 || bounceBackAmount.y > 0) {
this._curPageIdx = 0;
}
+
if (this.indicator) {
this.indicator._changedState();
}
}
else {
+ var moveOffset = this._touchBeganPosition.sub(this._touchEndPosition);
var index = this._curPageIdx, nextIndex = index + this._getDragDirection(moveOffset);
var timeInSecond = this.pageTurningSpeed * Math.abs(index - nextIndex);
if (nextIndex < this._pages.length) {
diff --git a/cocos2d/core/components/CCPageViewIndicator.js b/cocos2d/core/components/CCPageViewIndicator.js
index db34d5a6d2f..dee27c5dc8f 100644
--- a/cocos2d/core/components/CCPageViewIndicator.js
+++ b/cocos2d/core/components/CCPageViewIndicator.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -148,6 +148,7 @@ var PageViewIndicator = cc.Class({
var node = new cc.Node();
var sprite = node.addComponent(cc.Sprite);
sprite.spriteFrame = this.spriteFrame;
+ sprite.sizeMode = cc.Sprite.SizeMode.CUSTOM;
node.parent = this.node;
node.width = this.cellSize.width;
node.height = this.cellSize.height;
diff --git a/cocos2d/core/components/CCProgressBar.js b/cocos2d/core/components/CCProgressBar.js
index a90d987d1ab..4754c245fd0 100644
--- a/cocos2d/core/components/CCProgressBar.js
+++ b/cocos2d/core/components/CCProgressBar.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -261,7 +261,7 @@ var ProgressBar = cc.Class({
*/
progress: {
default: 1,
- type: 'Float',
+ type: cc.Float,
range: [0, 1, 0.1],
slide: true,
tooltip: CC_DEV && 'i18n:COMPONENT.progress.progress',
diff --git a/cocos2d/core/components/CCRenderComponent.js b/cocos2d/core/components/CCRenderComponent.js
index 4ff2a9f050a..c23fc4d9b20 100644
--- a/cocos2d/core/components/CCRenderComponent.js
+++ b/cocos2d/core/components/CCRenderComponent.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -23,12 +23,15 @@
THE SOFTWARE.
****************************************************************************/
+import Assembler from '../renderer/assembler';
+import MaterialVariant from '../assets/material/material-variant';
+import { Color } from '../value-types';
+
const Component = require('./CCComponent');
-const renderEngine = require('../renderer/render-engine');
const RenderFlow = require('../renderer/render-flow');
-const BlendFactor = require('../platform/CCMacro').BlendFactor;
-const RenderData = renderEngine.RenderData;
-const gfx = renderEngine.gfx;
+const Material = require('../assets/material/CCMaterial');
+
+let _temp_color = new Color();
/**
* !#en
@@ -49,62 +52,44 @@ let RenderComponent = cc.Class({
},
properties: {
- _srcBlendFactor: BlendFactor.SRC_ALPHA,
- _dstBlendFactor: BlendFactor.ONE_MINUS_SRC_ALPHA,
-
- /**
- * !#en specify the source Blend Factor, this will generate a custom material object, please pay attention to the memory cost.
- * !#zh 指定原图的混合模式,这会克隆一个新的材质对象,注意这带来的
- * @property srcBlendFactor
- * @type {macro.BlendFactor}
- * @example
- * sprite.srcBlendFactor = cc.macro.BlendFactor.ONE;
- */
- srcBlendFactor: {
- get: function() {
- return this._srcBlendFactor;
- },
- set: function(value) {
- if (this._srcBlendFactor === value) return;
- this._srcBlendFactor = value;
- this._updateBlendFunc(true);
- },
- animatable: false,
- type:BlendFactor,
- tooltip: CC_DEV && 'i18n:COMPONENT.sprite.src_blend_factor'
+ _materials: {
+ default: [],
+ type: Material,
},
/**
- * !#en specify the destination Blend Factor.
- * !#zh 指定目标的混合模式
- * @property dstBlendFactor
- * @type {macro.BlendFactor}
- * @example
- * sprite.dstBlendFactor = cc.macro.BlendFactor.ONE;
+ * !#en The materials used by this render component.
+ * !#zh 渲染组件使用的材质。
+ * @property {[Material]} sharedMaterials
*/
- dstBlendFactor: {
- get: function() {
- return this._dstBlendFactor;
+ materials: {
+ get () {
+ return this._materials;
},
- set: function(value) {
- if (this._dstBlendFactor === value) return;
- this._dstBlendFactor = value;
- this._updateBlendFunc(true);
+ set (val) {
+ this._materials = val;
+ this._activateMaterial();
},
- animatable: false,
- type: BlendFactor,
- tooltip: CC_DEV && 'i18n:COMPONENT.sprite.dst_blend_factor'
- },
+ type: [Material],
+ displayName: 'Materials',
+ animatable: false
+ }
},
ctor () {
- this._material = null;
- this._renderData = null;
- this.__allocedDatas = [];
- this._vertexFormat = null;
- this._toPostHandle = false;
- this._assembler = this.constructor._assembler;
- this._postAssembler = this.constructor._postAssembler;
+ this._vertsDirty = true;
+ this._assembler = null;
+ },
+
+ _resetAssembler () {
+ Assembler.init(this);
+ this._updateColor();
+ this.setVertsDirty();
+ },
+
+ __preload () {
+ this._resetAssembler();
+ this._activateMaterial();
},
onEnable () {
@@ -112,7 +97,9 @@ let RenderComponent = cc.Class({
this.node._renderComponent.enabled = false;
}
this.node._renderComponent = this;
- this.node._renderFlag |= RenderFlow.FLAG_RENDER | RenderFlow.FLAG_UPDATE_RENDER_DATA | RenderFlow.FLAG_COLOR;
+ this.node._renderFlag |= RenderFlow.FLAG_OPACITY_COLOR;
+
+ this.setVertsDirty();
},
onDisable () {
@@ -121,104 +108,149 @@ let RenderComponent = cc.Class({
},
onDestroy () {
- for (let i = 0, l = this.__allocedDatas.length; i < l; i++) {
- RenderData.free(this.__allocedDatas[i]);
+ let materials = this._materials;
+ for (let i = 0; i < materials.length; i++) {
+ cc.pool.material.put(materials[i]);
}
- this.__allocedDatas.length = 0;
- this._material = null;
- this._renderData = null;
+ materials.length = 0;
+
+ cc.pool.assembler.put(this._assembler);
+ },
+
+ setVertsDirty () {
+ this._vertsDirty = true;
+ this.markForRender(true);
+ },
+
+ _on3DNodeChanged () {
+ this._resetAssembler();
},
- _canRender () {
- return this._enabled;
+ _validateRender () {
},
- markForUpdateRenderData (enable) {
- if (enable && this._canRender()) {
- this.node._renderFlag |= RenderFlow.FLAG_UPDATE_RENDER_DATA;
- }
- else if (!enable) {
- this.node._renderFlag &= ~RenderFlow.FLAG_UPDATE_RENDER_DATA;
- }
+ markForValidate () {
+ cc.RenderFlow.registerValidate(this);
},
markForRender (enable) {
- if (enable && this._canRender()) {
- this.node._renderFlag |= RenderFlow.FLAG_RENDER;
+ let flag = RenderFlow.FLAG_RENDER | RenderFlow.FLAG_UPDATE_RENDER_DATA;
+ if (enable) {
+ this.node._renderFlag |= flag;
+ this.markForValidate();
}
- else if (!enable) {
- this.node._renderFlag &= ~RenderFlow.FLAG_RENDER;
+ else {
+ this.node._renderFlag &= ~flag;
}
},
- markForCustomIARender (enable) {
- if (enable && this._canRender()) {
- this.node._renderFlag |= RenderFlow.FLAG_CUSTOM_IA_RENDER;
+ disableRender () {
+ this.node._renderFlag &= ~(RenderFlow.FLAG_RENDER | RenderFlow.FLAG_UPDATE_RENDER_DATA);
+ },
+
+ /**
+ * !#en Get the material by index.
+ * !#zh 根据指定索引获取材质
+ * @method getMaterial
+ * @param {Number} index
+ * @return {MaterialVariant}
+ */
+ getMaterial (index) {
+ if (index < 0 || index >= this._materials.length) {
+ return null;
}
- else if (!enable) {
- this.node._renderFlag &= ~RenderFlow.FLAG_CUSTOM_IA_RENDER;
+
+ let material = this._materials[index];
+ if (!material) return null;
+
+ let instantiated = MaterialVariant.create(material, this);
+ if (instantiated !== material) {
+ this.setMaterial(index, instantiated);
}
- },
- disableRender () {
- this.node._renderFlag &= ~(RenderFlow.FLAG_RENDER | RenderFlow.FLAG_CUSTOM_IA_RENDER | RenderFlow.FLAG_UPDATE_RENDER_DATA | RenderFlow.FLAG_COLOR);
+ return instantiated;
},
- requestRenderData () {
- let data = RenderData.alloc();
- this.__allocedDatas.push(data);
- return data;
+ /**
+ * !#en Gets all the materials.
+ * !#zh 获取所有材质。
+ * @method getMaterials
+ * @return {[MaterialVariant]}
+ */
+ getMaterials () {
+ let materials = this._materials;
+ for (let i = 0; i < materials.length; i++) {
+ materials[i] = MaterialVariant.create(materials[i], this);
+ }
+ return materials;
},
-
- destroyRenderData (data) {
- let index = this.__allocedDatas.indexOf(data);
- if (index !== -1) {
- this.__allocedDatas.splice(index, 1);
- RenderData.free(data);
+
+ /**
+ * !#en Set the material by index.
+ * !#zh 根据指定索引设置材质
+ * @method setMaterial
+ * @param {Number} index
+ * @param {Material} material
+ * @return {Material}
+ */
+ setMaterial (index, material) {
+ if (material !== this._materials[index]) {
+ material = MaterialVariant.create(material, this);
+ this._materials[index] = material;
}
+ this._updateMaterial();
+ this.markForRender(true);
+ return material;
},
- _updateColor () {
- let material = this._material;
- if (material) {
- material.color = this.node.color;
- material.updateHash();
+ _getDefaultMaterial () {
+ return Material.getBuiltinMaterial('2d-sprite');
+ },
- // reset flag when set color to material successfully
- this.node._renderFlag &= ~RenderFlow.FLAG_COLOR;
+ /**
+ * Init material.
+ */
+ _activateMaterial () {
+ let materials = this._materials;
+ if (!materials[0]) {
+ let material = this._getDefaultMaterial();
+ materials[0] = material;
+ }
+
+ for (let i = 0; i < materials.length; i++) {
+ materials[i] = MaterialVariant.create(materials[i], this);
}
- },
- getMaterial () {
- return this._material;
+ this._updateMaterial();
},
- _updateMaterial (material) {
- this._material = material;
+ /**
+ * Update material properties.
+ */
+ _updateMaterial () {
- this._updateBlendFunc();
- material.updateHash();
},
-
- _updateBlendFunc: function (updateHash) {
- if (!this._material) {
- return;
- }
- var pass = this._material._mainTech.passes[0];
- pass.setBlend(
- gfx.BLEND_FUNC_ADD,
- this._srcBlendFactor, this._dstBlendFactor,
- gfx.BLEND_FUNC_ADD,
- this._srcBlendFactor, this._dstBlendFactor
- );
-
- if (updateHash) {
- this._material.updateHash();
+ _updateColor () {
+ if (this._assembler.updateColor) {
+ let premultiply = this.srcBlendFactor === cc.macro.BlendFactor.ONE;
+ premultiply && Color.premultiplyAlpha(_temp_color, this.node._color);
+ let color = premultiply ? _temp_color._val : null;
+ this._assembler.updateColor(this, color);
}
},
+
+ _checkBacth (renderer, cullingMask) {
+ let material = this._materials[0];
+ if ((material && material.getHash() !== renderer.material.getHash()) ||
+ renderer.cullingMask !== cullingMask) {
+ renderer._flush();
+
+ renderer.node = material.getDefine('CC_USE_MODEL') ? this.node : renderer._dummyNode;
+ renderer.material = material;
+ renderer.cullingMask = cullingMask;
+ }
+ }
});
-RenderComponent._assembler = null;
-RenderComponent._postAssembler = null;
-cc.RenderComponent = module.exports = RenderComponent;
\ No newline at end of file
+cc.RenderComponent = module.exports = RenderComponent;
diff --git a/cocos2d/core/components/CCRichText.js b/cocos2d/core/components/CCRichText.js
index aa4c890bb9e..af99d657313 100644
--- a/cocos2d/core/components/CCRichText.js
+++ b/cocos2d/core/components/CCRichText.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -34,6 +34,7 @@ const HorizontalAlign = macro.TextAlignment;
const VerticalAlign = macro.VerticalTextAlignment;
const RichTextChildName = "RICHTEXT_CHILD";
const RichTextChildImageName = "RICHTEXT_Image_CHILD";
+const CacheMode = cc.Label.CacheMode;
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
@@ -59,6 +60,7 @@ function debounce(func, wait, immediate) {
*/
let pool = new js.Pool(function (node) {
if (CC_EDITOR) {
+ cc.isValid(node) && node.destroy();
return false;
}
if (CC_DEV) {
@@ -66,47 +68,35 @@ let pool = new js.Pool(function (node) {
}
if (!cc.isValid(node)) {
return false;
+ } else {
+ let outline = node.getComponent(cc.LabelOutline);
+ if (outline) {
+ outline.width = 0;
+ }
}
- else if (node.getComponent(cc.LabelOutline)) {
- return false;
- }
+
return true;
}, 20);
-pool.get = function (string, fontAsset, fontSize) {
+pool.get = function (string, richtext) {
let labelNode = this._get();
if (!labelNode) {
labelNode = new cc.PrivateNode(RichTextChildName);
}
- let labelComponent = labelNode.getComponent(cc.Label);
- if (!labelComponent) {
- labelComponent = labelNode.addComponent(cc.Label);
- }
labelNode.setPosition(0, 0);
labelNode.setAnchorPoint(0.5, 0.5);
- labelNode.setContentSize(128, 128);
labelNode.skewX = 0;
- if (typeof string !== 'string') {
- string = '' + string;
- }
- let isAsset = fontAsset instanceof cc.Font;
- if (isAsset) {
- labelComponent.font = fontAsset;
- } else {
- labelComponent.fontFamily = "Arial";
+ let labelComponent = labelNode.getComponent(cc.Label);
+ if (!labelComponent) {
+ labelComponent = labelNode.addComponent(cc.Label);
}
- labelComponent.string = string;
+
+ labelComponent.string = "";
labelComponent.horizontalAlign = HorizontalAlign.LEFT;
- labelComponent.verticalAlign = VerticalAlign.TOP;
- labelComponent.fontSize = fontSize || 40;
- labelComponent.overflow = 0;
- labelComponent.enableWrapText = true;
- labelComponent.lineHeight = 40;
- labelComponent._enableBold(false);
- labelComponent._enableItalics(false);
- labelComponent._enableUnderline(false);
+ labelComponent.verticalAlign = VerticalAlign.CENTER;
+ labelComponent._forceUseCanvas = true;
return labelNode;
};
@@ -128,6 +118,7 @@ let RichText = cc.Class({
this._linesWidth = [];
if (CC_EDITOR) {
+ this._userDefinedFont = null;
this._updateRichTextStatus = debounce(this._updateRichText, 200);
}
else {
@@ -138,6 +129,7 @@ let RichText = cc.Class({
editor: CC_EDITOR && {
menu: 'i18n:MAIN_MENU.component.renderers/RichText',
help: 'i18n:COMPONENT.help_url.richtext',
+ inspector: 'packages://inspector/inspectors/comps/richtext.js',
executeInEditMode: true
},
@@ -190,6 +182,26 @@ let RichText = cc.Class({
}
},
+ /**
+ * !#en Custom System font of RichText
+ * !#zh 富文本定制系统字体
+ * @property {String} fontFamily
+ */
+ _fontFamily: "Arial",
+ fontFamily: {
+ tooltip: CC_DEV && 'i18n:COMPONENT.richtext.font_family',
+ get () {
+ return this._fontFamily;
+ },
+ set (value) {
+ if (this._fontFamily === value) return;
+ this._fontFamily = value;
+ this._layoutDirty = true;
+ this._updateRichTextStatus();
+ },
+ animatable: false
+ },
+
/**
* !#en Custom TTF font of RichText
* !#zh 富文本定制字体
@@ -204,12 +216,69 @@ let RichText = cc.Class({
this._layoutDirty = true;
if (this.font) {
+ if (CC_EDITOR) {
+ this._userDefinedFont = this.font;
+ }
+ this.useSystemFont = false;
this._onTTFLoaded();
}
+ else {
+ this.useSystemFont = true;
+ }
this._updateRichTextStatus();
}
},
+ /**
+ * !#en Whether use system font name or not.
+ * !#zh 是否使用系统字体。
+ * @property {Boolean} useSystemFont
+ */
+ _isSystemFontUsed: true,
+ useSystemFont: {
+ get () {
+ return this._isSystemFontUsed;
+ },
+ set (value) {
+ if (this._isSystemFontUsed === value) {
+ return;
+ }
+ this._isSystemFontUsed = value;
+
+ if (CC_EDITOR) {
+ if (value) {
+ this.font = null;
+ }
+ else if (this._userDefinedFont) {
+ this.font = this._userDefinedFont;
+ return;
+ }
+ }
+
+ this._layoutDirty = true;
+ this._updateRichTextStatus();
+ },
+ animatable: false,
+ tooltip: CC_DEV && 'i18n:COMPONENT.richtext.system_font',
+ },
+
+ /**
+ * !#en The cache mode of label. This mode only supports system fonts.
+ * !#zh 文本缓存模式, 该模式只支持系统字体。
+ * @property {Label.CacheMode} cacheMode
+ */
+ cacheMode: {
+ default: CacheMode.NONE,
+ type: CacheMode,
+ tooltip: CC_DEV && 'i18n:COMPONENT.label.cacheMode',
+ notify (oldValue) {
+ if (this.cacheMode === oldValue) return;
+
+ this._updateRichTextStatus();
+ },
+ animatable: false
+ },
+
/**
* !#en The maximize width of the RichText
* !#zh 富文本的最大宽度
@@ -304,22 +373,31 @@ let RichText = cc.Class({
this._onTTFLoaded();
},
+ _onColorChanged (parentColor) {
+ let children = this.node.children;
+ children.forEach(function (childNode) {
+ childNode.color = parentColor;
+ });
+ },
+
_addEventListeners () {
this.node.on(cc.Node.EventType.TOUCH_END, this._onTouchEnded, this);
+ this.node.on(cc.Node.EventType.COLOR_CHANGED, this._onColorChanged, this);
},
_removeEventListeners () {
this.node.off(cc.Node.EventType.TOUCH_END, this._onTouchEnded, this);
+ this.node.off(cc.Node.EventType.COLOR_CHANGED, this._onColorChanged, this);
},
_updateLabelSegmentTextAttributes () {
this._labelSegments.forEach(function (item) {
- this._applyTextAttribute(item);
+ this._applyTextAttribute(item, null, true);
}.bind(this));
},
_createFontLabel (string) {
- return pool.get(string, this.font, this.fontSize);
+ return pool.get(string, this);
},
_onTTFLoaded () {
@@ -330,7 +408,7 @@ let RichText = cc.Class({
}
else {
let self = this;
- cc.loader.load(this.font.nativeUrl, function (err, fontFamily) {
+ cc.assetManager.postLoadNative(this.font, function (err) {
self._layoutDirty = true;
self._updateRichText();
});
@@ -349,13 +427,11 @@ let RichText = cc.Class({
if (self._labelSegmentsCache.length === 0) {
label = self._createFontLabel(string);
self._labelSegmentsCache.push(label);
- }
- else {
+ } else {
label = self._labelSegmentsCache[0];
- label.getComponent(cc.Label).string = string;
}
label._styleIndex = styleIndex;
- self._applyTextAttribute(label);
+ self._applyTextAttribute(label, string, true);
let labelSize = label.getContentSize();
return labelSize.width;
};
@@ -373,10 +449,11 @@ let RichText = cc.Class({
for (let i = 0; i < this._labelSegments.length; ++i) {
let labelSegment = this._labelSegments[i];
let clickHandler = labelSegment._clickHandler;
+ let clickParam = labelSegment._clickParam;
if (clickHandler && this._containsTouchLocation(labelSegment, event.touch.getLocation())) {
components.forEach(function (component) {
if (component.enabledInHierarchy && component[clickHandler]) {
- component[clickHandler](event);
+ component[clickHandler](event, clickParam);
}
});
event.stopPropagation();
@@ -442,16 +519,15 @@ let RichText = cc.Class({
let labelSegment;
if (this._labelSegmentsCache.length === 0) {
labelSegment = this._createFontLabel(stringToken);
- }
- else {
+ } else {
labelSegment = this._labelSegmentsCache.pop();
- labelSegment.getComponent(cc.Label).string = stringToken;
}
labelSegment._styleIndex = styleIndex;
labelSegment._lineCount = this._lineCount;
+ labelSegment.active = this.node.active;
labelSegment.setAnchorPoint(0, 0);
- this._applyTextAttribute(labelSegment);
+ this._applyTextAttribute(labelSegment, stringToken);
this.node.addChild(labelSegment);
this._labelSegments.push(labelSegment);
@@ -537,31 +613,34 @@ let RichText = cc.Class({
return true;
}
else {
- if (oldItem.style) {
- if (newItem.style) {
- if (!!newItem.style.outline !== !!oldItem.style.outline) {
+ let oldStyle = oldItem.style, newStyle = newItem.style;
+ if (oldStyle) {
+ if (newStyle) {
+ if (!oldStyle.outline !== !newStyle.outline) {
return true;
}
- if (oldItem.style.size !== newItem.style.size
- || oldItem.style.italic !== newItem.style.italic
- || oldItem.style.isImage !== newItem.style.isImage) {
+ if (oldStyle.size !== newStyle.size
+ || !oldStyle.italic !== !newStyle.italic
+ || oldStyle.isImage !== newStyle.isImage) {
return true;
}
- if (oldItem.style.isImage === newItem.style.isImage) {
- if (oldItem.style.src !== newItem.style.src) {
- return true;
- }
+ if (oldStyle.src !== newStyle.src ||
+ oldStyle.imageAlign !== newStyle.imageAlign ||
+ oldStyle.imageHeight !== newStyle.imageHeight ||
+ oldStyle.imageWidth !== newStyle.imageWidth ||
+ oldStyle.imageOffset !== newStyle.imageOffset) {
+ return true;
}
}
else {
- if (oldItem.style.size || oldItem.style.italic || oldItem.style.isImage || oldItem.style.outline) {
+ if (oldStyle.size || oldStyle.italic || oldStyle.isImage || oldStyle.outline) {
return true;
}
}
}
else {
- if (newItem.style) {
- if (newItem.style.size || newItem.style.italic || newItem.style.isImage || newItem.style.outline) {
+ if (newStyle) {
+ if (newStyle.size || newStyle.italic || newStyle.isImage || newStyle.outline) {
return true;
}
}
@@ -577,7 +656,19 @@ let RichText = cc.Class({
if (spriteFrame) {
let spriteNode = new cc.PrivateNode(RichTextChildImageName);
let spriteComponent = spriteNode.addComponent(cc.Sprite);
- spriteNode.setAnchorPoint(0, 0);
+ switch (richTextElement.style.imageAlign)
+ {
+ case 'top':
+ spriteNode.setAnchorPoint(0, 1);
+ break;
+ case 'center':
+ spriteNode.setAnchorPoint(0, 0.5);
+ break;
+ default:
+ spriteNode.setAnchorPoint(0, 0);
+ break;
+ }
+ if (richTextElement.style.imageOffset) spriteNode._imageOffset = richTextElement.style.imageOffset;
spriteComponent.type = cc.Sprite.Type.SLICED;
spriteComponent.sizeMode = cc.Sprite.SizeMode.CUSTOM;
this.node.addChild(spriteNode);
@@ -590,8 +681,7 @@ let RichText = cc.Class({
let expectWidth = richTextElement.style.imageWidth;
let expectHeight = richTextElement.style.imageHeight;
- //follow the original rule, expectHeight must less then lineHeight
- if (expectHeight > 0 && expectHeight < this.lineHeight) {
+ if (expectHeight > 0) {
scaleFactor = expectHeight / spriteHeight;
spriteWidth = spriteWidth * scaleFactor;
spriteHeight = spriteHeight * scaleFactor;
@@ -625,6 +715,15 @@ let RichText = cc.Class({
if (richTextElement.style.event.click) {
spriteNode._clickHandler = richTextElement.style.event.click;
}
+ if (richTextElement.style.event.param) {
+ spriteNode._clickParam = richTextElement.style.event.param;
+ }
+ else {
+ spriteNode._clickParam = '';
+ }
+ }
+ else {
+ spriteNode._clickHandler = null;
}
}
else {
@@ -633,7 +732,7 @@ let RichText = cc.Class({
},
_updateRichText () {
- if (!this.enabled) return;
+ if (!this.enabledInHierarchy) return;
let newTextArray = _htmlTextParser.parse(this.string);
if (!this._needsUpdateTextLayout(newTextArray)) {
@@ -709,7 +808,7 @@ let RichText = cc.Class({
if (this.maxWidth > 0) {
this._labelWidth = this.maxWidth;
}
- this._labelHeight = this._lineCount * this.lineHeight;
+ this._labelHeight = (this._lineCount + textUtils.BASELINE_RATIO) * this.lineHeight;
// trigger "size-changed" event
this.node.setContentSize(this._labelWidth, this._labelHeight);
@@ -773,6 +872,46 @@ let RichText = cc.Class({
if (lineCount === nextLineIndex) {
nextTokenX += labelSize.width;
}
+
+ let sprite = label.getComponent(cc.Sprite);
+ if (sprite) {
+ // adjust img align (from )
+ let lineHeightSet = this.lineHeight;
+ let lineHeightReal = this.lineHeight * (1 + textUtils.BASELINE_RATIO); //single line node height
+ switch (label.anchorY)
+ {
+ case 1:
+ label.y += ( lineHeightSet + ( ( lineHeightReal - lineHeightSet) / 2 ) );
+ break;
+ case 0.5:
+ label.y += ( lineHeightReal / 2 );
+ break;
+ default:
+ label.y += ( (lineHeightReal - lineHeightSet) / 2 );
+ break;
+ }
+ // adjust img offset (from )
+ if (label._imageOffset)
+ {
+ let offsets = label._imageOffset.split(',');
+ if (offsets.length === 1 && offsets[0])
+ {
+ let offsetY = parseFloat(offsets[0]);
+ if (Number.isInteger(offsetY)) label.y += offsetY;
+ }
+ else if(offsets.length === 2)
+ {
+ let offsetX = parseFloat(offsets[0]);
+ let offsetY = parseFloat(offsets[1]);
+ if (Number.isInteger(offsetX)) label.x += offsetX;
+ if (Number.isInteger(offsetY)) label.y += offsetY;
+ }
+ }
+ }
+
+ //adjust y for label with outline
+ let outline = label.getComponent(cc.LabelOutline);
+ if (outline && outline.width) label.y = label.y - outline.width;
}
},
@@ -787,16 +926,14 @@ let RichText = cc.Class({
}
},
- _applyTextAttribute (labelNode) {
+ // When string is null, it means that the text does not need to be updated.
+ _applyTextAttribute (labelNode, string, force) {
let labelComponent = labelNode.getComponent(cc.Label);
if (!labelComponent) {
return;
}
let index = labelNode._styleIndex;
- labelComponent.lineHeight = this.lineHeight;
- labelComponent.horizontalAlign = HorizontalAlign.LEFT;
- labelComponent.verticalAlign = VerticalAlign.CENTER;
let textStyle = null;
if (this._textArray[index]) {
@@ -806,18 +943,28 @@ let RichText = cc.Class({
if (textStyle && textStyle.color) {
labelNode.color = this._convertLiteralColorValue(textStyle.color);
}else {
- labelNode.color = this._convertLiteralColorValue("white");
+ labelNode.color = this.node.color;
}
- labelComponent._enableBold(textStyle && textStyle.bold);
+ labelComponent.cacheMode = this.cacheMode;
+
+ let isAsset = this.font instanceof cc.Font;
+ if (isAsset && !this._isSystemFontUsed) {
+ labelComponent.font = this.font;
+ } else {
+ labelComponent.fontFamily = this.fontFamily;
+ }
- labelComponent._enableItalics(textStyle && textStyle.italic);
+ labelComponent.useSystemFont = this._isSystemFontUsed;
+ labelComponent.lineHeight = this.lineHeight;
+ labelComponent.enableBold = textStyle && textStyle.bold;
+ labelComponent.enableItalics = textStyle && textStyle.italic;
//TODO: temporary implementation, the italic effect should be implemented in the internal of label-assembler.
if (textStyle && textStyle.italic) {
labelNode.skewX = 12;
}
- labelComponent._enableUnderline(textStyle && textStyle.underline);
+ labelComponent.enableUnderline = textStyle && textStyle.underline;
if (textStyle && textStyle.outline) {
let labelOutlineComponent = labelNode.getComponent(cc.LabelOutline);
@@ -835,12 +982,28 @@ let RichText = cc.Class({
labelComponent.fontSize = this.fontSize;
}
- labelComponent._updateRenderData(true);
+ if (string !== null) {
+ if (typeof string !== 'string') {
+ string = '' + string;
+ }
+ labelComponent.string = string;
+ }
+
+ force && labelComponent._forceUpdateRenderData();
if (textStyle && textStyle.event) {
if (textStyle.event.click) {
labelNode._clickHandler = textStyle.event.click;
}
+ if (textStyle.event.param) {
+ labelNode._clickParam = textStyle.event.param;
+ }
+ else {
+ labelNode._clickParam = '';
+ }
+ }
+ else {
+ labelNode._clickHandler = null;
}
},
diff --git a/cocos2d/core/components/CCSafeArea.js b/cocos2d/core/components/CCSafeArea.js
new file mode 100644
index 00000000000..e79ddec120c
--- /dev/null
+++ b/cocos2d/core/components/CCSafeArea.js
@@ -0,0 +1,111 @@
+/****************************************************************************
+ Copyright (c) 2020 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+const Widget = require('./CCWidget');
+const WidgetManager = require('../base-ui/CCWidgetManager');
+/**
+ * !#en
+ * This component is used to adjust the layout of current node to respect the safe area of a notched mobile device such as the iPhone X.
+ * It is typically used for the top node of the UI interaction area. For specific usage, refer to the official [example-cases/02_ui/16_safeArea/SafeArea.fire](https://github.com/cocos-creator/example-cases).
+ *
+ * The concept of safe area is to give you a fixed inner rectangle in which you can safely display content that will be drawn on screen.
+ * You are strongly discouraged from providing controls outside of this area. But your screen background could embellish edges.
+ *
+ * This component internally uses the API `cc.sys.getSafeAreaRect();` to obtain the safe area of the current iOS or Android device,
+ * and implements the adaptation by using the Widget component and set anchor.
+ *
+ * !#zh
+ * 该组件会将所在节点的布局适配到 iPhone X 等异形屏手机的安全区域内,通常用于 UI 交互区域的顶层节点,具体用法可参考官方范例 [example-cases/02_ui/16_safeArea/SafeArea.fire](https://github.com/cocos-creator/example-cases)。
+ *
+ * 该组件内部通过 API `cc.sys.getSafeAreaRect();` 获取到当前 iOS 或 Android 设备的安全区域,并通过 Widget 组件实现适配。
+ *
+ * @class SafeArea
+ * @extends Component
+ */
+var SafeArea = cc.Class({
+ name: 'cc.SafeArea',
+ extends: require('./CCComponent'),
+
+ editor: CC_EDITOR && {
+ help: 'i18n:COMPONENT.help_url.safe_area',
+ menu: 'i18n:MAIN_MENU.component.ui/SafeArea',
+ inspector: 'packages://inspector/inspectors/comps/safe-area.js',
+ executeInEditMode: true,
+ requireComponent: Widget,
+ },
+
+ onEnable () {
+ this.updateArea();
+ cc.view.on('canvas-resize', this.updateArea, this);
+ },
+
+ onDisable () {
+ cc.view.off('canvas-resize', this.updateArea, this);
+ },
+
+ /**
+ * !#en Adapt to safe area
+ * !#zh 立即适配安全区域
+ * @method updateArea
+ * @example
+ * let safeArea = this.node.addComponent(cc.SafeArea);
+ * safeArea.updateArea();
+ */
+ updateArea () {
+ // TODO Remove Widget dependencies in the future
+ let widget = this.node.getComponent(Widget);
+ if (!widget) {
+ return;
+ }
+
+ if (CC_EDITOR) {
+ widget.top = widget.bottom = widget.left = widget.right = 0;
+ widget.isAlignTop = widget.isAlignBottom = widget.isAlignLeft = widget.isAlignRight = true;
+ return;
+ }
+ // IMPORTANT: need to update alignment to get the latest position
+ widget.updateAlignment();
+ let lastPos = this.node.position;
+ let lastAnchorPoint = this.node.getAnchorPoint();
+ //
+ widget.isAlignTop = widget.isAlignBottom = widget.isAlignLeft = widget.isAlignRight = true;
+ let screenWidth = cc.winSize.width, screenHeight = cc.winSize.height;
+ let safeArea = cc.sys.getSafeAreaRect();
+ widget.top = screenHeight - safeArea.y - safeArea.height;
+ widget.bottom = safeArea.y;
+ widget.left = safeArea.x;
+ widget.right = screenWidth - safeArea.x - safeArea.width;
+ widget.updateAlignment();
+ // set anchor, keep the original position unchanged
+ let curPos = this.node.position;
+ let anchorX = lastAnchorPoint.x - (curPos.x - lastPos.x) / this.node.width;
+ let anchorY = lastAnchorPoint.y - (curPos.y - lastPos.y) / this.node.height;
+ this.node.setAnchorPoint(anchorX, anchorY);
+ // IMPORTANT: restore to lastPos even if widget is not ALWAYS
+ WidgetManager.add(widget);
+ }
+});
+
+cc.SafeArea = module.exports = SafeArea;
diff --git a/cocos2d/core/components/CCScrollBar.js b/cocos2d/core/components/CCScrollBar.js
index 070f28dbd3b..a9d51e5a285 100644
--- a/cocos2d/core/components/CCScrollBar.js
+++ b/cocos2d/core/components/CCScrollBar.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -136,8 +136,11 @@ var Scrollbar = cc.Class({
},
_convertToScrollViewSpace: function(content) {
- var worldSpacePos = content.convertToWorldSpace(cc.v2(0, 0));
- var scrollViewSpacePos = this._scrollView.node.convertToNodeSpace(worldSpacePos);
+ let scrollViewNode = this._scrollView.node;
+ var worldSpacePos = content.convertToWorldSpaceAR(cc.v2(-content.anchorX * content.width, -content.anchorY * content.height));
+ var scrollViewSpacePos = scrollViewNode.convertToNodeSpaceAR(worldSpacePos);
+ scrollViewSpacePos.x += scrollViewNode.anchorX * scrollViewNode.width;
+ scrollViewSpacePos.y += scrollViewNode.anchorY * scrollViewNode.height;
return scrollViewSpacePos;
},
diff --git a/cocos2d/core/components/CCScrollView.js b/cocos2d/core/components/CCScrollView.js
index 8c32b746b0b..1cb321f5afc 100644
--- a/cocos2d/core/components/CCScrollView.js
+++ b/cocos2d/core/components/CCScrollView.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -31,6 +31,9 @@ const OUT_OF_BOUNDARY_BREAKING_FACTOR = 0.05;
const EPSILON = 1e-4;
const MOVEMENT_FACTOR = 0.7;
+let _tempPoint = cc.v2();
+let _tempPrevPoint = cc.v2();
+
let quintEaseOut = function(time) {
time -= 1;
return (time * time * time * time * time + 1);
@@ -160,6 +163,7 @@ let ScrollView = cc.Class({
editor: CC_EDITOR && {
menu: 'i18n:MAIN_MENU.component.ui/ScrollView',
help: 'i18n:COMPONENT.help_url.scrollview',
+ inspector: 'packages://inspector/inspectors/comps/scrollview.js',
executeInEditMode: false,
},
@@ -253,7 +257,7 @@ let ScrollView = cc.Class({
*/
brake: {
default: 0.5,
- type: 'Float',
+ type: cc.Float,
range: [0, 1, 0.1],
tooltip: CC_DEV && 'i18n:COMPONENT.scrollview.brake',
},
@@ -338,6 +342,15 @@ let ScrollView = cc.Class({
default: true,
animatable: false,
tooltip: CC_DEV && 'i18n:COMPONENT.scrollview.cancelInnerEvents'
+ },
+
+ // private object
+ _view: {
+ get: function () {
+ if (this.content) {
+ return this.content.parent;
+ }
+ }
}
},
@@ -600,10 +613,10 @@ let ScrollView = cc.Class({
* @return {Vec2} - A Vec2 value indicate the maximize scroll offset in x and y axis.
*/
getMaxScrollOffset () {
- let scrollSize = this.node.getContentSize();
+ let viewSize = this._view.getContentSize();
let contentSize = this.content.getContentSize();
- let horizontalMaximizeOffset = contentSize.width - scrollSize.width;
- let verticalMaximizeOffset = contentSize.height - scrollSize.height;
+ let horizontalMaximizeOffset = contentSize.width - viewSize.width;
+ let verticalMaximizeOffset = contentSize.height - viewSize.height;
horizontalMaximizeOffset = horizontalMaximizeOffset >= 0 ? horizontalMaximizeOffset : 0;
verticalMaximizeOffset = verticalMaximizeOffset >=0 ? verticalMaximizeOffset : 0;
@@ -719,7 +732,7 @@ let ScrollView = cc.Class({
* !#en Query the content's position in its parent space.
* !#zh 获取当前视图内容的坐标点。
* @method getContentPosition
- * @returns {Position} - The content's position in its parent space.
+ * @returns {Vec2} - The content's position in its parent space.
*/
getContentPosition () {
return this.content.getPosition();
@@ -768,7 +781,7 @@ let ScrollView = cc.Class({
let deltaMove = cc.v2(0, 0);
let wheelPrecision = -0.1;
- if(CC_JSB) {
+ if(CC_JSB || CC_RUNTIME) {
wheelPrecision = -7;
}
if(this.vertical) {
@@ -797,16 +810,18 @@ let ScrollView = cc.Class({
if (!currentOutOfBoundary.fuzzyEquals(cc.v2(0, 0), EPSILON)) {
this._processInertiaScroll();
this.unschedule(this._checkMouseWheel);
+ this._dispatchEvent('scroll-ended');
this._stopMouseWheel = false;
return;
}
this._mouseWheelEventElapsedTime += dt;
- //mouse wheel event is ended
+ // mouse wheel event is ended
if (this._mouseWheelEventElapsedTime > maxElapsedTime) {
this._onScrollBarTouchEnded();
this.unschedule(this._checkMouseWheel);
+ this._dispatchEvent('scroll-ended');
this._stopMouseWheel = false;
}
},
@@ -819,7 +834,7 @@ let ScrollView = cc.Class({
anchor = anchor.clampf(cc.v2(0, 0), cc.v2(1, 1));
- let scrollSize = this.node.getContentSize();
+ let scrollSize = this._view.getContentSize();
let contentSize = this.content.getContentSize();
let bottomDeta = this._getContentBottomBoundary() - this._bottomBoundary;
bottomDeta = -bottomDeta;
@@ -856,30 +871,14 @@ let ScrollView = cc.Class({
if (contentSize.height < scrollViewSize.height) {
totalScrollDelta = contentSize.height - scrollViewSize.height;
moveDelta.y = bottomDeta - totalScrollDelta;
-
- if (this.verticalScrollBar) {
- this.verticalScrollBar.hide();
- }
- } else {
- if (this.verticalScrollBar) {
- this.verticalScrollBar.show();
- }
}
if (contentSize.width < scrollViewSize.width) {
totalScrollDelta = contentSize.width - scrollViewSize.width;
moveDelta.x = leftDeta;
-
- if (this.horizontalScrollBar) {
- this.horizontalScrollBar.hide();
- }
-
- } else {
- if (this.horizontalScrollBar) {
- this.horizontalScrollBar.show();
- }
}
+ this._updateScrollBarState();
this._moveContent(moveDelta);
this._adjustContentOutOfBoundary();
},
@@ -891,26 +890,21 @@ let ScrollView = cc.Class({
if(layout && layout.enabledInHierarchy) {
layout.updateLayout();
}
- let viewSize = this.content.parent.getContentSize();
+ let viewSize = this._view.getContentSize();
+
+ let anchorX = viewSize.width * this._view.anchorX;
+ let anchorY = viewSize.height * this._view.anchorY;
- let leftBottomPosition = this._convertToContentParentSpace(cc.v2(0, 0));
- this._leftBoundary = leftBottomPosition.x;
- this._bottomBoundary = leftBottomPosition.y;
+ this._leftBoundary = -anchorX;
+ this._bottomBoundary = -anchorY;
- let topRightPosition = this._convertToContentParentSpace(cc.v2(viewSize.width, viewSize.height));
- this._rightBoundary = topRightPosition.x;
- this._topBoundary = topRightPosition.y;
+ this._rightBoundary = this._leftBoundary + viewSize.width;
+ this._topBoundary = this._bottomBoundary + viewSize.height;
this._moveContentToTopLeft(viewSize);
}
},
- _convertToContentParentSpace (position) {
- let contentParent = this.content.parent;
- let viewPositionInWorldSpace = contentParent.convertToWorldSpace(position);
- return contentParent.convertToNodeSpaceAR(viewPositionInWorldSpace);
- },
-
//this is for nested scrollview
_hasNestedViewGroup (event, captureListeners) {
if (event.eventPhase !== cc.Event.CAPTURING_PHASE) return;
@@ -1000,7 +994,7 @@ let ScrollView = cc.Class({
this._stopPropagationIfTargetIsMe(event);
}
},
-
+
_onTouchCancelled (event, captureListeners) {
if (!this.enabledInHierarchy) return;
if (this._hasNestedViewGroup(event, captureListeners)) return;
@@ -1020,8 +1014,15 @@ let ScrollView = cc.Class({
this._gatherTouchMove(deltaMove);
},
+ // Contains node angle calculations
+ _getLocalAxisAlignDelta (touch) {
+ this.node.convertToNodeSpaceAR(touch.getLocation(), _tempPoint);
+ this.node.convertToNodeSpaceAR(touch.getPreviousLocation(), _tempPrevPoint);
+ return _tempPoint.sub(_tempPrevPoint);
+ },
+
_handleMoveLogic (touch) {
- let deltaMove = touch.getDelta();
+ let deltaMove = this._getLocalAxisAlignDelta(touch);
this._processDeltaMove(deltaMove);
},
@@ -1046,7 +1047,7 @@ let ScrollView = cc.Class({
if (realMove.y > 0) { //up
let icBottomPos = this.content.y - this.content.anchorY * this.content.height;
- if (icBottomPos + realMove.y > this._bottomBoundary) {
+ if (icBottomPos + realMove.y >= this._bottomBoundary) {
scrollEventType = 'scroll-to-bottom';
}
}
@@ -1057,7 +1058,7 @@ let ScrollView = cc.Class({
scrollEventType = 'scroll-to-top';
}
}
- else if (realMove.x < 0) { //left
+ if (realMove.x < 0) { //left
let icRightPos = this.content.x - this.content.anchorX * this.content.width + this.content.width;
if (icRightPos + realMove.x <= this._rightBoundary) {
scrollEventType = 'scroll-to-right';
@@ -1102,7 +1103,7 @@ let ScrollView = cc.Class({
_clampDelta (delta) {
let contentSize = this.content.getContentSize();
- let scrollViewSize = this.node.getContentSize();
+ let scrollViewSize = this._view.getContentSize();
if (contentSize.width < scrollViewSize.width) {
delta.x = 0;
}
@@ -1167,10 +1168,9 @@ let ScrollView = cc.Class({
},
_handleReleaseLogic (touch) {
- let delta = touch.getDelta();
+ let delta = this._getLocalAxisAlignDelta(touch);
this._gatherTouchMove(delta);
this._processInertiaScroll();
-
if (this._scrolling) {
this._scrolling = false;
if (!this._autoScrolling) {
@@ -1250,8 +1250,10 @@ let ScrollView = cc.Class({
this._moveContent(this._clampDelta(deltaMove), reachedEnd);
this._dispatchEvent('scrolling');
+ // scollTo API controll move
if (!this._autoScrolling) {
this._isBouncing = false;
+ this._scrolling = false;
this._dispatchEvent('scroll-ended');
}
},
@@ -1276,7 +1278,7 @@ let ScrollView = cc.Class({
let targetDelta = deltaMove.normalize();
let contentSize = this.content.getContentSize();
- let scrollviewSize = this.node.getContentSize();
+ let scrollviewSize = this._view.getContentSize();
let totalMoveWidth = (contentSize.width - scrollviewSize.width);
let totalMoveHeight = (contentSize.height - scrollviewSize.height);
@@ -1419,6 +1421,29 @@ let ScrollView = cc.Class({
return outOfBoundaryAmount;
},
+ _updateScrollBarState () {
+ if (!this.content) {
+ return;
+ }
+ let contentSize = this.content.getContentSize();
+ let scrollViewSize = this._view.getContentSize();
+ if (this.verticalScrollBar) {
+ if (contentSize.height < scrollViewSize.height) {
+ this.verticalScrollBar.hide();
+ } else {
+ this.verticalScrollBar.show();
+ }
+ }
+
+ if (this.horizontalScrollBar) {
+ if (contentSize.width < scrollViewSize.width) {
+ this.horizontalScrollBar.hide();
+ } else {
+ this.horizontalScrollBar.show();
+ }
+ }
+ },
+
_updateScrollBar (outOfBoundary) {
if (this.horizontalScrollBar) {
this.horizontalScrollBar._onScroll(outOfBoundary);
@@ -1501,28 +1526,16 @@ let ScrollView = cc.Class({
}
},
- _showScrollbar () {
- if (this.horizontalScrollBar) {
- this.horizontalScrollBar.show();
- }
-
- if (this.verticalScrollBar) {
- this.verticalScrollBar.show();
- }
- },
-
onDisable () {
if (!CC_EDITOR) {
this._unregisterEvent();
- this.node.off(NodeEvent.SIZE_CHANGED, this._calculateBoundary, this);
- this.node.off(NodeEvent.SCALE_CHANGED, this._calculateBoundary, this);
if (this.content) {
this.content.off(NodeEvent.SIZE_CHANGED, this._calculateBoundary, this);
this.content.off(NodeEvent.SCALE_CHANGED, this._calculateBoundary, this);
- if (this.content.parent) {
- this.content.parent.off(NodeEvent.POSITION_CHANGED, this._calculateBoundary, this);
- this.content.parent.off(NodeEvent.SCALE_CHANGED, this._calculateBoundary, this);
- this.content.parent.off(NodeEvent.SIZE_CHANGED, this._calculateBoundary, this);
+ if (this._view) {
+ this._view.off(NodeEvent.POSITION_CHANGED, this._calculateBoundary, this);
+ this._view.off(NodeEvent.SCALE_CHANGED, this._calculateBoundary, this);
+ this._view.off(NodeEvent.SIZE_CHANGED, this._calculateBoundary, this);
}
}
}
@@ -1533,19 +1546,17 @@ let ScrollView = cc.Class({
onEnable () {
if (!CC_EDITOR) {
this._registerEvent();
- this.node.on(NodeEvent.SIZE_CHANGED, this._calculateBoundary, this);
- this.node.on(NodeEvent.SCALE_CHANGED, this._calculateBoundary, this);
if (this.content) {
this.content.on(NodeEvent.SIZE_CHANGED, this._calculateBoundary, this);
this.content.on(NodeEvent.SCALE_CHANGED, this._calculateBoundary, this);
- if (this.content.parent) {
- this.content.parent.on(NodeEvent.POSITION_CHANGED, this._calculateBoundary, this);
- this.content.parent.on(NodeEvent.SCALE_CHANGED, this._calculateBoundary, this);
- this.content.parent.on(NodeEvent.SIZE_CHANGED, this._calculateBoundary, this);
+ if (this._view) {
+ this._view.on(NodeEvent.POSITION_CHANGED, this._calculateBoundary, this);
+ this._view.on(NodeEvent.SCALE_CHANGED, this._calculateBoundary, this);
+ this._view.on(NodeEvent.SIZE_CHANGED, this._calculateBoundary, this);
}
}
}
- this._showScrollbar();
+ this._updateScrollBarState();
},
update (dt) {
diff --git a/cocos2d/core/components/CCSlider.js b/cocos2d/core/components/CCSlider.js
index 11e0b270a0e..b77d72fc168 100644
--- a/cocos2d/core/components/CCSlider.js
+++ b/cocos2d/core/components/CCSlider.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -113,8 +113,8 @@ var Slider = cc.Class({
},
/**
- * !#en The slider events callback
- * !#zh 滑动器组件事件回调函数
+ * !#en The slider slide events' callback array
+ * !#zh 滑动器组件滑动事件回调函数数组
* @property {Component.EventHandler[]} slideEvents
*/
slideEvents: {
@@ -203,12 +203,13 @@ var Slider = cc.Class({
_updateProgress: function (touch) {
if (!this.handle) { return; }
- var localTouchPos = this.node.convertToNodeSpaceAR(touch.getLocation());
+ let node = this.node;
+ var localTouchPos = node.convertToNodeSpaceAR(touch.getLocation());
if (this.direction === Direction.Horizontal) {
- this.progress = misc.clamp01(0.5 + (localTouchPos.x - this._offset.x) / this.node.width);
+ this.progress = misc.clamp01((localTouchPos.x - this._offset.x + node.anchorX * node.width) / node.width);
}
else {
- this.progress = misc.clamp01(0.5 + (localTouchPos.y - this._offset.y) / this.node.height);
+ this.progress = misc.clamp01((localTouchPos.y - this._offset.y + node.anchorY * node.height) / node.height);
}
},
diff --git a/cocos2d/core/components/CCSprite.js b/cocos2d/core/components/CCSprite.js
index cd2de5ab180..cd97b07a781 100644
--- a/cocos2d/core/components/CCSprite.js
+++ b/cocos2d/core/components/CCSprite.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -27,10 +27,8 @@
const misc = require('../utils/misc');
const NodeEvent = require('../CCNode').EventType;
const RenderComponent = require('./CCRenderComponent');
-const RenderFlow = require('../renderer/render-flow');
-const renderEngine = require('../renderer/render-engine');
-const SpriteMaterial = renderEngine.SpriteMaterial;
-const GraySpriteMaterial = renderEngine.GraySpriteMaterial;
+const BlendFunc = require('../utils/blend-func');
+
/**
* !#en Enum for sprite type.
@@ -121,7 +119,12 @@ var SizeMode = cc.Enum({
*/
RAW: 2
});
-
+/**
+ * !#en Sprite state can choice the normal or grayscale.
+ * !#zh 精灵颜色通道模式。
+ * @enum Sprite.State
+ * @deprecated
+ */
var State = cc.Enum({
/**
* !#en The normal state
@@ -141,7 +144,8 @@ var State = cc.Enum({
* !#en Renders a sprite in the scene.
* !#zh 该组件用于在场景中渲染精灵。
* @class Sprite
- * @extends Component
+ * @extends RenderComponent
+ * @uses BlendFunc
* @example
* // Create a new node and add sprite components.
* var node = new cc.Node("New Sprite");
@@ -151,12 +155,7 @@ var State = cc.Enum({
var Sprite = cc.Class({
name: 'cc.Sprite',
extends: RenderComponent,
-
- ctor () {
- this._assembler = null;
- this._graySpriteMaterial = null;
- this._spriteMaterial = null;
- },
+ mixins: [BlendFunc],
editor: CC_EDITOR && {
menu: 'i18n:MAIN_MENU.component.renderers/Sprite',
@@ -176,7 +175,6 @@ var Sprite = cc.Class({
_fillStart: 0,
_fillRange: 0,
_isTrimmedMode: true,
- _state: 0,
_atlas: {
default: null,
type: cc.SpriteAtlas,
@@ -195,10 +193,10 @@ var Sprite = cc.Class({
* sprite.spriteFrame = newSpriteFrame;
*/
spriteFrame: {
- get: function () {
+ get () {
return this._spriteFrame;
},
- set: function (value, force) {
+ set (value, force) {
var lastSprite = this._spriteFrame;
if (CC_EDITOR) {
if (!force && ((lastSprite && lastSprite._uuid) === (value && value._uuid))) {
@@ -211,8 +209,6 @@ var Sprite = cc.Class({
}
}
this._spriteFrame = value;
- // render & update render data flag will be triggered while applying new sprite frame
- this.markForUpdateRenderData(false);
this._applySpriteFrame(lastSprite);
if (CC_EDITOR) {
this.node.emit('spriteframe-changed', this);
@@ -230,15 +226,14 @@ var Sprite = cc.Class({
* sprite.type = cc.Sprite.Type.SIMPLE;
*/
type: {
- get: function () {
+ get () {
return this._type;
},
- set: function (value) {
+ set (value) {
if (this._type !== value) {
- this.destroyRenderData(this._renderData);
- this._renderData = null;
this._type = value;
- this._updateAssembler();
+ this.setVertsDirty();
+ this._resetAssembler();
}
},
type: SpriteType,
@@ -257,20 +252,14 @@ var Sprite = cc.Class({
* sprite.fillType = cc.Sprite.FillType.HORIZONTAL;
*/
fillType : {
- get: function () {
+ get () {
return this._fillType;
},
- set: function(value) {
+ set (value) {
if (value !== this._fillType) {
- if (value === FillType.RADIAL || this._fillType === FillType.RADIAL) {
- this.destroyRenderData(this._renderData);
- this._renderData = null;
- }
- else if (this._renderData) {
- this.markForUpdateRenderData(true);
- }
this._fillType = value;
- this._updateAssembler();
+ this.setVertsDirty();
+ this._resetAssembler();
}
},
type: FillType,
@@ -288,14 +277,14 @@ var Sprite = cc.Class({
* sprite.fillCenter = new cc.Vec2(0, 0);
*/
fillCenter: {
- get: function() {
+ get () {
return this._fillCenter;
},
- set: function(value) {
+ set (value) {
this._fillCenter.x = value.x;
this._fillCenter.y = value.y;
- if (this._type === SpriteType.FILLED && this._renderData) {
- this.markForUpdateRenderData(true);
+ if (this._type === SpriteType.FILLED) {
+ this.setVertsDirty();
}
},
tooltip: CC_DEV && 'i18n:COMPONENT.sprite.fill_center',
@@ -313,13 +302,13 @@ var Sprite = cc.Class({
* sprite.fillStart = 0.5;
*/
fillStart: {
- get: function() {
+ get () {
return this._fillStart;
},
- set: function(value) {
+ set (value) {
this._fillStart = misc.clampf(value, -1, 1);
- if (this._type === SpriteType.FILLED && this._renderData) {
- this.markForUpdateRenderData(true);
+ if (this._type === SpriteType.FILLED) {
+ this.setVertsDirty();
}
},
tooltip: CC_DEV && 'i18n:COMPONENT.sprite.fill_start'
@@ -337,13 +326,13 @@ var Sprite = cc.Class({
* sprite.fillRange = 1;
*/
fillRange: {
- get: function() {
+ get () {
return this._fillRange;
},
- set: function(value) {
+ set (value) {
this._fillRange = misc.clampf(value, -1, 1);
- if (this._type === SpriteType.FILLED && this._renderData) {
- this.markForUpdateRenderData(true);
+ if (this._type === SpriteType.FILLED) {
+ this.setVertsDirty();
}
},
tooltip: CC_DEV && 'i18n:COMPONENT.sprite.fill_range'
@@ -357,15 +346,14 @@ var Sprite = cc.Class({
* sprite.trim = true;
*/
trim: {
- get: function () {
+ get () {
return this._isTrimmedMode;
},
- set: function (value) {
+ set (value) {
if (this._isTrimmedMode !== value) {
this._isTrimmedMode = value;
- if ((this._type === SpriteType.SIMPLE || this._type === SpriteType.MESH) &&
- this._renderData) {
- this.markForUpdateRenderData(true);
+ if (this._type === SpriteType.SIMPLE || this._type === SpriteType.MESH) {
+ this.setVertsDirty();
}
}
},
@@ -383,10 +371,10 @@ var Sprite = cc.Class({
* sprite.sizeMode = cc.Sprite.SizeMode.CUSTOM;
*/
sizeMode: {
- get: function () {
+ get () {
return this._sizeMode;
},
- set: function (value) {
+ set (value) {
this._sizeMode = value;
if (value !== SizeMode.CUSTOM) {
this._applySpriteSize();
@@ -405,7 +393,7 @@ var Sprite = cc.Class({
State: State,
},
- setVisible: function (visible) {
+ setVisible (visible) {
this.enabled = visible;
},
@@ -414,121 +402,60 @@ var Sprite = cc.Class({
* @method setState
* @see `Sprite.State`
* @param state {Sprite.State} NORMAL or GRAY State.
+ * @deprecated
*/
- setState: function (state) {
- if (this._state === state) return;
- this._state = state;
- this._activateMaterial();
- },
+ setState () {},
/**
* Gets the current state.
* @method getState
* @see `Sprite.State`
* @return {Sprite.State}
+ * @deprecated
*/
- getState: function () {
- return this._state;
- },
+ getState () {},
- onEnable: function () {
+ __preload () {
this._super();
-
- if (!this._spriteFrame || !this._spriteFrame.textureLoaded()) {
- // Do not render when sprite frame is not ready
- this.disableRender();
- if (this._spriteFrame) {
- this._spriteFrame.once('load', this._onTextureLoaded, this);
- this._spriteFrame.ensureLoadTexture();
- }
- }
-
- this._updateAssembler();
- this._activateMaterial();
-
- this.node.on(NodeEvent.SIZE_CHANGED, this._onNodeSizeDirty, this);
- this.node.on(NodeEvent.ANCHOR_CHANGED, this._onNodeSizeDirty, this);
+ CC_EDITOR && this.node.on(NodeEvent.SIZE_CHANGED, this._resizedInEditor, this);
+ this._applySpriteFrame();
},
- onDisable: function () {
+ onEnable () {
this._super();
+ this._spriteFrame && this._spriteFrame.ensureLoadTexture();
- this.node.off(NodeEvent.SIZE_CHANGED, this._onNodeSizeDirty, this);
- this.node.off(NodeEvent.ANCHOR_CHANGED, this._onNodeSizeDirty, this);
- },
-
- _onNodeSizeDirty () {
- if (!this._renderData) return;
- this.markForUpdateRenderData(true);
+ this.node.on(cc.Node.EventType.SIZE_CHANGED, this.setVertsDirty, this);
+ this.node.on(cc.Node.EventType.ANCHOR_CHANGED, this.setVertsDirty, this);
},
- _updateAssembler: function () {
- let assembler = Sprite._assembler.getAssembler(this);
+ onDisable () {
+ this._super();
- if (this._assembler !== assembler) {
- this._assembler = assembler;
- this._renderData = null;
- }
-
- if (!this._renderData) {
- this._renderData = this._assembler.createData(this);
- this._renderData.material = this._material;
- this.markForUpdateRenderData(true);
- }
+ this.node.off(cc.Node.EventType.SIZE_CHANGED, this.setVertsDirty, this);
+ this.node.off(cc.Node.EventType.ANCHOR_CHANGED, this.setVertsDirty, this);
},
- _activateMaterial: function () {
- let spriteFrame = this._spriteFrame;
-
- // WebGL
- if (cc.game.renderType !== cc.game.RENDER_TYPE_CANVAS) {
- // Get material
- let material;
- if (this._state === State.GRAY) {
- if (!this._graySpriteMaterial) {
- this._graySpriteMaterial = new GraySpriteMaterial();
- }
- material = this._graySpriteMaterial;
- }
- else {
- if (!this._spriteMaterial) {
- this._spriteMaterial = new SpriteMaterial();
- }
- material = this._spriteMaterial;
- }
- // Set texture
- if (spriteFrame && spriteFrame.textureLoaded()) {
- let texture = spriteFrame.getTexture();
- if (material.texture !== texture) {
- material.texture = texture;
- this._updateMaterial(material);
- }
- else if (material !== this._material) {
- this._updateMaterial(material);
- }
- if (this._renderData) {
- this._renderData.material = material;
- }
-
- this.node._renderFlag |= RenderFlow.FLAG_COLOR;
- this.markForUpdateRenderData(true);
- this.markForRender(true);
- }
- else {
- this.disableRender();
+ _updateMaterial () {
+ let texture = this._spriteFrame && this._spriteFrame.getTexture();
+
+ // make sure material is belong to self.
+ let material = this.getMaterial(0);
+ if (material) {
+ if (material.getDefine('USE_TEXTURE') !== undefined) {
+ material.define('USE_TEXTURE', true);
}
+ material.setProperty('texture', texture);
}
- else {
- this.markForUpdateRenderData(true);
- this.markForRender(true);
- }
+
+ BlendFunc.prototype._updateMaterial.call(this);
},
_applyAtlas: CC_EDITOR && function (spriteFrame) {
// Set atlas
if (spriteFrame && spriteFrame._atlasUuid) {
var self = this;
- cc.AssetLibrary.loadAsset(spriteFrame._atlasUuid, function (err, asset) {
+ cc.assetManager.loadAny(spriteFrame._atlasUuid, function (err, asset) {
self._atlas = asset;
});
} else {
@@ -536,91 +463,62 @@ var Sprite = cc.Class({
}
},
- _canRender () {
- if (cc.game.renderType === cc.game.RENDER_TYPE_CANVAS) {
- if (!this._enabled) return false;
- }
- else {
- if (!this._enabled || !this._material) return false;
- }
-
+ _validateRender () {
let spriteFrame = this._spriteFrame;
- if (!spriteFrame || !spriteFrame.textureLoaded()) {
- return false;
- }
- return true;
- },
-
- markForUpdateRenderData (enable) {
- if (enable && this._canRender()) {
- this.node._renderFlag |= RenderFlow.FLAG_UPDATE_RENDER_DATA;
-
- let renderData = this._renderData;
- if (renderData) {
- renderData.uvDirty = true;
- renderData.vertDirty = true;
- }
- }
- else if (!enable) {
- this.node._renderFlag &= ~RenderFlow.FLAG_UPDATE_RENDER_DATA;
- }
- },
-
- _applySpriteSize: function () {
- if (this._spriteFrame) {
- if (SizeMode.RAW === this._sizeMode) {
- var size = this._spriteFrame.getOriginalSize();
- this.node.setContentSize(size);
- } else if (SizeMode.TRIMMED === this._sizeMode) {
- var rect = this._spriteFrame.getRect();
- this.node.setContentSize(rect.width, rect.height);
- }
-
- this._activateMaterial();
- }
- },
-
- _onTextureLoaded: function () {
- if (!this.isValid) {
+ if (this._materials[0] &&
+ spriteFrame &&
+ spriteFrame.textureLoaded()) {
return;
}
- this._applySpriteSize();
+ this.disableRender();
},
- _applySpriteFrame: function (oldFrame) {
- if (oldFrame && oldFrame.off) {
- oldFrame.off('load', this._onTextureLoaded, this);
+ _applySpriteSize () {
+ if (!this._spriteFrame || !this.isValid) return;
+
+ if (SizeMode.RAW === this._sizeMode) {
+ var size = this._spriteFrame._originalSize;
+ this.node.setContentSize(size);
+ } else if (SizeMode.TRIMMED === this._sizeMode) {
+ var rect = this._spriteFrame._rect;
+ this.node.setContentSize(rect.width, rect.height);
}
+
+ this.setVertsDirty();
+ },
- var spriteFrame = this._spriteFrame;
- if (!spriteFrame || (this._material && this._material._texture) !== (spriteFrame && spriteFrame._texture)) {
- // disable render flow until texture is loaded
- this.markForRender(false);
+ _applySpriteFrame (oldFrame) {
+ let oldTexture = oldFrame && oldFrame.getTexture();
+ if (oldTexture && !oldTexture.loaded) {
+ oldFrame.off('load', this._applySpriteSize, this);
}
+ this._updateMaterial();
+ let spriteFrame = this._spriteFrame;
if (spriteFrame) {
- if (!oldFrame || spriteFrame._texture !== oldFrame._texture) {
- if (spriteFrame.textureLoaded()) {
- this._onTextureLoaded(null);
- }
- else {
- spriteFrame.once('load', this._onTextureLoaded, this);
- spriteFrame.ensureLoadTexture();
- }
+ let newTexture = spriteFrame.getTexture();
+ if (newTexture && newTexture.loaded) {
+ this._applySpriteSize();
}
else {
- this._applySpriteSize();
+ this.disableRender();
+ spriteFrame.once('load', this._applySpriteSize, this);
}
}
+ else {
+ this.disableRender();
+ }
if (CC_EDITOR) {
// Set atlas
this._applyAtlas(spriteFrame);
}
},
+});
- _resized: CC_EDITOR && function () {
+if (CC_EDITOR) {
+ Sprite.prototype._resizedInEditor = function () {
if (this._spriteFrame) {
var actualSize = this.node.getContentSize();
var expectedW = actualSize.width;
@@ -640,21 +538,13 @@ var Sprite = cc.Class({
this._sizeMode = SizeMode.CUSTOM;
}
}
- },
-});
-
-if (CC_EDITOR) {
- // override __preload
- Sprite.prototype.__superPreload = cc.Component.prototype.__preload;
- Sprite.prototype.__preload = function () {
- if (this.__superPreload) this.__superPreload();
- this.node.on(NodeEvent.SIZE_CHANGED, this._resized, this);
};
+
// override onDestroy
Sprite.prototype.__superOnDestroy = cc.Component.prototype.onDestroy;
Sprite.prototype.onDestroy = function () {
if (this.__superOnDestroy) this.__superOnDestroy();
- this.node.off(NodeEvent.SIZE_CHANGED, this._resized, this);
+ this.node.off(NodeEvent.SIZE_CHANGED, this._resizedInEditor, this);
};
}
diff --git a/cocos2d/core/components/CCStudioComponent.js b/cocos2d/core/components/CCStudioComponent.js
index 3b673f3cc2f..c9b6b6f48e4 100644
--- a/cocos2d/core/components/CCStudioComponent.js
+++ b/cocos2d/core/components/CCStudioComponent.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -244,7 +244,7 @@ var StudioComponent = cc.Class({
sliderProgress: {
default: 0.5,
readonly: true,
- type: 'Float',
+ type: cc.Float,
range: [0, 1, 0.1]
},
@@ -288,31 +288,18 @@ var StudioComponent = cc.Class({
},
});
-var PrefabHelper = require('../utils/prefab-helper');
-StudioComponent.PlaceHolder = cc.Class({
- name: 'cc.StudioComponent.PlaceHolder',
- extends: cc.Component,
- properties: {
- _baseUrl: '',
- nestedPrefab: cc.Prefab,
- },
- onLoad: function () {
- if (!this.nestedPrefab) {
- if (CC_DEV) {
- cc.warn('Unable to find %s resource.', this._baseUrl);
- }
- return;
- }
- this._replaceWithNestedPrefab();
+cc.StudioComponent = module.exports = StudioComponent;
+
+
+var StudioWidget = cc.Class({
+ name: 'cc.StudioWidget',
+ extends: cc.Widget,
+ editor: CC_EDITOR && {
+ inspector: 'packages://inspector/inspectors/comps/ccwidget.js',
},
- _replaceWithNestedPrefab: function () {
- var node = this.node;
- var _prefab = node._prefab;
- _prefab.root = node;
- _prefab.asset = this.nestedPrefab;
- PrefabHelper.syncWithPrefab(node);
- }
+ _validateTargetInDEV () {}
});
-cc.StudioComponent = module.exports = StudioComponent;
+cc.StudioWidget = module.exports = StudioWidget;
+
diff --git a/cocos2d/core/components/CCToggle.js b/cocos2d/core/components/CCToggle.js
index 5f546d8e89a..69da98f0131 100644
--- a/cocos2d/core/components/CCToggle.js
+++ b/cocos2d/core/components/CCToggle.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -24,16 +24,20 @@
THE SOFTWARE.
****************************************************************************/
+const GraySpriteState = require('../utils/gray-sprite-state');
+
/**
* !#en The toggle component is a CheckBox, when it used together with a ToggleGroup, it
* could be treated as a RadioButton.
* !#zh Toggle 是一个 CheckBox,当它和 ToggleGroup 一起使用的时候,可以变成 RadioButton。
* @class Toggle
* @extends Button
+ * @uses GraySpriteState
*/
-var Toggle = cc.Class({
+let Toggle = cc.Class({
name: 'cc.Toggle',
extends: require('./CCButton'),
+ mixins: [GraySpriteState],
editor: CC_EDITOR && {
menu: 'i18n:MAIN_MENU.component.ui/Toggle',
help: 'i18n:COMPONENT.help_url.toggle',
@@ -47,12 +51,36 @@ var Toggle = cc.Class({
* !#zh 如果这个设置为 true,则 check mark 组件会处于 enabled 状态,否则处于 disabled 状态。
* @property {Boolean} isChecked
*/
+ _N$isChecked: true,
isChecked: {
- default: true,
- tooltip: CC_DEV && 'i18n:COMPONENT.toggle.isChecked',
- notify: function () {
+ get: function () {
+ return this._N$isChecked;
+ },
+ set: function (value) {
+ if (value === this._N$isChecked) {
+ return;
+ }
+
+ var group = this.toggleGroup || this._toggleContainer;
+ if (group && group.enabled && this._N$isChecked) {
+ if (!group.allowSwitchOff) {
+ return;
+ }
+
+ }
+
+ this._N$isChecked = value;
this._updateCheckMark();
- }
+
+ if (group && group.enabled) {
+ group.updateToggles(this);
+ }
+
+ if (cc.Toggle._triggerEventInScript_isChecked) {
+ this._emitToggleEvents();
+ }
+ },
+ tooltip: CC_DEV && 'i18n:COMPONENT.toggle.isChecked',
},
/**
@@ -100,12 +128,17 @@ var Toggle = cc.Class({
},
+ statics: {
+ _triggerEventInScript_check: false,
+ _triggerEventInScript_isChecked: false,
+ },
+
onEnable: function () {
this._super();
if (!CC_EDITOR) {
this._registerToggleEvent();
}
- if (this.toggleGroup && this.toggleGroup.enabled) {
+ if (this.toggleGroup && this.toggleGroup.enabledInHierarchy) {
this.toggleGroup.addToggle(this);
}
},
@@ -115,62 +148,20 @@ var Toggle = cc.Class({
if (!CC_EDITOR) {
this._unregisterToggleEvent();
}
- if (this.toggleGroup && this.toggleGroup.enabled) {
+ if (this.toggleGroup && this.toggleGroup.enabledInHierarchy) {
this.toggleGroup.removeToggle(this);
}
},
- _updateCheckMark: function () {
- if (this.checkMark) {
- this.checkMark.node.active = !!this.isChecked;
- }
- },
-
- _updateDisabledState: function () {
- this._super();
-
- if (this.checkMark) {
- this.checkMark.setState(0);
- }
- if (this.enableAutoGrayEffect) {
- if (this.checkMark && !this.interactable) {
- this.checkMark.setState(1);
- }
- }
- },
-
- _registerToggleEvent: function () {
- this.node.on('click', this.toggle, this);
- },
-
- _unregisterToggleEvent: function () {
- this.node.off('click', this.toggle, this);
+ _hideCheckMark () {
+ this._N$isChecked = false;
+ this._updateCheckMark();
},
toggle: function (event) {
- var group = this.toggleGroup || this._toggleContainer;
-
- if (group && group.enabled && this.isChecked) {
- if (!group.allowSwitchOff) {
- return;
- }
- }
-
this.isChecked = !this.isChecked;
-
- this._updateCheckMark();
-
- if (group && group.enabled) {
- group.updateToggles(this);
- }
-
- this._emitToggleEvents(event);
- },
-
- _emitToggleEvents: function () {
- this.node.emit('toggle', this);
- if (this.checkEvents) {
- cc.Component.EventHandler.emitEvents(this.checkEvents, this);
+ if (!cc.Toggle._triggerEventInScript_isChecked && (cc.Toggle._triggerEventInScript_check || event)) {
+ this._emitToggleEvents();
}
},
@@ -180,21 +171,10 @@ var Toggle = cc.Class({
* @method check
*/
check: function () {
- var group = this.toggleGroup || this._toggleContainer;
-
- if (group && group.enabled && this.isChecked) {
- if (!group.allowSwitchOff) {
- return;
- }
- }
-
this.isChecked = true;
-
- if (group && group.enabled) {
- group.updateToggles(this);
+ if (!cc.Toggle._triggerEventInScript_isChecked && cc.Toggle._triggerEventInScript_check) {
+ this._emitToggleEvents();
}
-
- this._emitToggleEvents();
},
/**
@@ -203,28 +183,51 @@ var Toggle = cc.Class({
* @method uncheck
*/
uncheck: function () {
- var group = this.toggleGroup || this._toggleContainer;
+ this.isChecked = false;
+ if (!cc.Toggle._triggerEventInScript_isChecked && cc.Toggle._triggerEventInScript_check) {
+ this._emitToggleEvents();
+ }
+ },
- if (group && group.enabled && this.isChecked) {
- if (!group.allowSwitchOff) {
- return;
- }
+ _updateCheckMark: function () {
+ if (this.checkMark) {
+ this.checkMark.node.active = !!this.isChecked;
}
+ },
- this.isChecked = false;
+ _updateDisabledState: function () {
+ this._super();
+
+ if (this.enableAutoGrayEffect && this.checkMark) {
+ let useGrayMaterial = !this.interactable;
+ this._switchGrayMaterial(useGrayMaterial, this.checkMark);
+ }
+ },
+
+ _registerToggleEvent: function () {
+ this.node.on('click', this.toggle, this);
+ },
- this._emitToggleEvents();
+ _unregisterToggleEvent: function () {
+ this.node.off('click', this.toggle, this);
+ },
+
+ _emitToggleEvents: function () {
+ this.node.emit('toggle', this);
+ if (this.checkEvents) {
+ cc.Component.EventHandler.emitEvents(this.checkEvents, this);
+ }
}
+
});
cc.Toggle = module.exports = Toggle;
-
-var js = require('../platform/js');
+const js = require('../platform/js');
js.get(Toggle.prototype, '_toggleContainer',
function () {
- var parent = this.node.parent;
+ let parent = this.node.parent;
if (cc.Node.isNode(parent)) {
return parent.getComponent(cc.ToggleContainer);
}
diff --git a/cocos2d/core/components/CCToggleContainer.js b/cocos2d/core/components/CCToggleContainer.js
index 3d5801ba213..e4460f2501e 100644
--- a/cocos2d/core/components/CCToggleContainer.js
+++ b/cocos2d/core/components/CCToggleContainer.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -55,21 +55,39 @@ var ToggleContainer = cc.Class({
tooltip: CC_DEV && 'i18n:COMPONENT.toggle_group.allowSwitchOff',
default: false
},
+
+ /**
+ * !#en If Toggle is clicked, it will trigger event's handler
+ * !#zh Toggle 按钮的点击事件列表。
+ * @property {Component.EventHandler[]} checkEvents
+ */
+ checkEvents: {
+ default: [],
+ type: cc.Component.EventHandler
+ },
},
updateToggles: function (toggle) {
- this.toggleItems.forEach(function (item) {
- if (toggle.isChecked && item !== toggle) {
- item.isChecked = false;
+ if(!this.enabledInHierarchy) return;
+
+ if (toggle.isChecked) {
+ this.toggleItems.forEach(function (item) {
+ if (item !== toggle && item.isChecked && item.enabled) {
+ item._hideCheckMark();
+ }
+ });
+
+ if (this.checkEvents) {
+ cc.Component.EventHandler.emitEvents(this.checkEvents, toggle);
}
- });
+ }
},
_allowOnlyOneToggleChecked: function () {
var isChecked = false;
this.toggleItems.forEach(function (item) {
if (isChecked) {
- item.isChecked = false;
+ item._hideCheckMark();
}
else if (item.isChecked) {
isChecked = true;
@@ -113,7 +131,9 @@ var ToggleContainer = cc.Class({
var js = require('../platform/js');
js.get(ToggleContainer.prototype, 'toggleItems',
function () {
- return this.node.getComponentsInChildren(cc.Toggle);
+ return this.node._children.map(function (item) {
+ return item.getComponent(cc.Toggle);
+ }).filter(Boolean);
}
);
diff --git a/cocos2d/core/components/CCToggleGroup.js b/cocos2d/core/components/CCToggleGroup.js
index 035598aa626..7821e56b715 100644
--- a/cocos2d/core/components/CCToggleGroup.js
+++ b/cocos2d/core/components/CCToggleGroup.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -74,7 +74,7 @@ var ToggleGroup = cc.Class({
this._toggleItems.forEach(function (item){
if(toggle.isChecked) {
if (item !== toggle && item.isChecked && item.enabled) {
- item.isChecked = false;
+ item._hideCheckMark();
}
}
});
@@ -100,7 +100,7 @@ var ToggleGroup = cc.Class({
var isChecked = false;
this._toggleItems.forEach(function (item) {
if(isChecked && item.enabled) {
- item.isChecked = false;
+ item._hideCheckMark();
}
if (item.isChecked && item.enabled) {
@@ -130,7 +130,7 @@ var js = require('../platform/js');
var showed = false;
js.get(cc, 'ToggleGroup', function () {
if (!showed) {
- cc.logID(1405, 'cc.ToggleGroup', 'cc.ToggleContainer');
+ cc.errorID(1405, 'cc.ToggleGroup', 'cc.ToggleContainer');
showed = true;
}
return ToggleGroup;
diff --git a/cocos2d/core/components/CCViewGroup.js b/cocos2d/core/components/CCViewGroup.js
index 04b7b2f79f5..2561c245139 100644
--- a/cocos2d/core/components/CCViewGroup.js
+++ b/cocos2d/core/components/CCViewGroup.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/components/CCWidget.js b/cocos2d/core/components/CCWidget.js
index be959046461..754106d5089 100644
--- a/cocos2d/core/components/CCWidget.js
+++ b/cocos2d/core/components/CCWidget.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -576,9 +576,21 @@ var Widget = cc.Class({
WidgetManager.remove(this);
},
+ _validateTargetInDEV: CC_DEV && function () {
+ var target = this._target;
+ if (target) {
+ var isParent = this.node !== target && this.node.isChildOf(target);
+ if (!isParent) {
+ cc.errorID(6500);
+ this._target = null;
+ }
+ }
+
+ },
+
_setAlign: function (flag, isAlign) {
var current = (this._alignFlags & flag) > 0;
- if (isAlign == current) {
+ if (isAlign === current) {
return;
}
var isHorizontal = (flag & LEFT_RIGHT) > 0;
diff --git a/cocos2d/core/components/SubContextView.js b/cocos2d/core/components/SubContextView.js
new file mode 100644
index 00000000000..5a036f73913
--- /dev/null
+++ b/cocos2d/core/components/SubContextView.js
@@ -0,0 +1,255 @@
+/****************************************************************************
+ Copyright (c) 2020 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+const Component = require('./CCComponent');
+
+/**
+ * !#en SubContextView is a view component which controls open data context viewport in minigame platform.
+ * The component's node size decide the viewport of the sub context content in main context,
+ * the entire sub context texture will be scaled to the node's bounding box area.
+ * This component provides multiple important features:
+ * 1. Sub context could use its own resolution size and policy.
+ * 2. Sub context could be minized to smallest size it needed.
+ * 3. Resolution of sub context content could be increased.
+ * 4. User touch input is transformed to the correct viewport.
+ * 5. Texture update is handled by this component. User don't need to worry.
+ * One important thing to be noted, whenever the node's bounding box change,
+ * !#zh SubContextView 可以用来控制小游戏平台开放数据域在主域中的视窗的位置。
+ * 这个组件的节点尺寸决定了开放数据域内容在主域中的尺寸,整个开放数据域会被缩放到节点的包围盒范围内。
+ * 在这个组件的控制下,用户可以更自由得控制开放数据域:
+ * 1. 子域中可以使用独立的设计分辨率和适配模式
+ * 2. 子域区域尺寸可以缩小到只容纳内容即可
+ * 3. 子域的分辨率也可以被放大,以便获得更清晰的显示效果
+ * 4. 用户输入坐标会被自动转换到正确的子域视窗中
+ * 5. 子域内容贴图的更新由组件负责,用户不需要处理
+ * @class SubContextView
+ * @extends Component
+ */
+let SubContextView = cc.Class({
+ name: 'cc.SubContextView',
+ extends: Component,
+
+ editor: CC_EDITOR && {
+ menu: 'i18n:MAIN_MENU.component.others/SubContextView',
+ help: 'i18n:COMPONENT.help_url.subcontext_view',
+ },
+
+ properties: {
+ _firstlyEnabled: true,
+
+ _fps: 60,
+
+ fps: {
+ get () {
+ return this._fps;
+ },
+ set (value) {
+ if (this._fps === value) {
+ return;
+ }
+ this._fps = value;
+ this._updateInterval = 1 / value;
+ this._updateSubContextFrameRate();
+ },
+ tooltip: CC_DEV && 'i18n:COMPONENT.subcontext_view.fps'
+ }
+ },
+
+ ctor () {
+ this._sprite = null;
+ this._tex = new cc.Texture2D();
+ this._context = null;
+ this._updatedTime = performance.now();
+ this._updateInterval = 0;
+ },
+
+ onLoad () {
+ // Setup subcontext canvas size
+ if (window.__globalAdapter && __globalAdapter.getOpenDataContext) {
+ this._updateInterval = 1000 / this._fps;
+ this._context = __globalAdapter.getOpenDataContext();
+ this.reset();
+ let sharedCanvas = this._context.canvas;
+ this._tex.setPremultiplyAlpha(true);
+ this._tex.initWithElement(sharedCanvas);
+
+ this._sprite = this.node.getComponent(cc.Sprite);
+ if (!this._sprite) {
+ this._sprite = this.node.addComponent(cc.Sprite);
+ this._sprite.srcBlendFactor = cc.macro.BlendFactor.ONE;
+ }
+ this._sprite.spriteFrame = new cc.SpriteFrame(this._tex);
+ }
+ else {
+ this.enabled = false;
+ }
+ },
+
+ /**
+ * !#en Reset open data context size and viewport
+ * !#zh 重置开放数据域的尺寸和视窗
+ * @method reset
+ */
+ reset () {
+ if (this._context) {
+ this.updateSubContextViewport();
+ let sharedCanvas = this._context.canvas;
+ if (sharedCanvas) {
+ sharedCanvas.width = this.node.width;
+ sharedCanvas.height = this.node.height;
+ }
+ }
+ },
+
+ onEnable () {
+ if (this._firstlyEnabled && this._context) {
+ this._context.postMessage({
+ fromEngine: true,
+ event: 'boot',
+ });
+ this._firstlyEnabled = false;
+ }
+ else {
+ this._runSubContextMainLoop();
+ }
+ this._registerNodeEvent();
+ this._updateSubContextFrameRate();
+ this.updateSubContextViewport();
+ },
+
+ onDisable () {
+ this._unregisterNodeEvent();
+ this._stopSubContextMainLoop();
+ },
+
+ update (dt) {
+ let calledUpdateMannually = (dt === undefined);
+ if (calledUpdateMannually) {
+ this._context && this._context.postMessage({
+ fromEngine: true,
+ event: 'step',
+ });
+ this._updateSubContextTexture();
+ return;
+ }
+ let now = performance.now();
+ let deltaTime = (now - this._updatedTime);
+ if (deltaTime >= this._updateInterval) {
+ this._updatedTime += this._updateInterval;
+ this._updateSubContextTexture();
+ }
+ },
+
+ _updateSubContextTexture () {
+ if (!this._tex || !this._context) {
+ return;
+ }
+ this._tex.initWithElement(this._context.canvas);
+ this._sprite._activateMaterial();
+ },
+
+ /**
+ * !#en Update the sub context viewport manually, it should be called whenever the node's bounding box changes.
+ * !#zh 更新开放数据域相对于主域的 viewport,这个函数应该在节点包围盒改变时手动调用。
+ * @method updateSubContextViewport
+ */
+ updateSubContextViewport () {
+ if (this._context) {
+ let box = this.node.getBoundingBoxToWorld();
+ let sx = cc.view._scaleX;
+ let sy = cc.view._scaleY;
+ this._context.postMessage({
+ fromEngine: true,
+ event: 'viewport',
+ x: box.x * sx + cc.view._viewportRect.x,
+ y: box.y * sy + cc.view._viewportRect.y,
+ width: box.width * sx,
+ height: box.height * sy
+ });
+ }
+ },
+
+ _registerNodeEvent () {
+ this.node.on('position-changed', this.updateSubContextViewport, this);
+ this.node.on('scale-changed', this.updateSubContextViewport, this);
+ this.node.on('size-changed', this.updateSubContextViewport, this);
+ },
+
+ _unregisterNodeEvent () {
+ this.node.off('position-changed', this.updateSubContextViewport, this);
+ this.node.off('scale-changed', this.updateSubContextViewport, this);
+ this.node.off('size-changed', this.updateSubContextViewport, this);
+ },
+
+ _runSubContextMainLoop () {
+ if (this._context) {
+ this._context.postMessage({
+ fromEngine: true,
+ event: 'mainLoop',
+ value: true,
+ });
+ }
+ },
+
+ _stopSubContextMainLoop () {
+ if (this._context) {
+ this._context.postMessage({
+ fromEngine: true,
+ event: 'mainLoop',
+ value: false,
+ });
+ }
+ },
+
+ _updateSubContextFrameRate () {
+ if (this._context) {
+ this._context.postMessage({
+ fromEngine: true,
+ event: 'frameRate',
+ value: this._fps,
+ });
+ }
+ },
+});
+
+cc.SubContextView = module.exports = SubContextView;
+
+/**
+ * !#en WXSubContextView is deprecated since v2.4.1, please use SubContextView instead.
+ * !#zh 自 v2.4.1 起,WXSubContextView 已经废弃,请使用 SubContextView
+ * @class WXSubContextView
+ * @extends Component
+ * @deprecated since v2.4.1
+ */
+cc.WXSubContextView = SubContextView;
+
+/**
+ * !#en SwanSubContextView is deprecated since v2.4.1, please use SubContextView instead.
+ * !#zh 自 v2.4.1 起,SwanSubContextView 已经废弃,请使用 SubContextView
+ * @class SwanSubContextView
+ * @extends Component
+ * @deprecated since v2.4.1
+ */
+cc.SwanSubContextView = SubContextView;
\ No newline at end of file
diff --git a/cocos2d/core/components/WXSubContextView.js b/cocos2d/core/components/WXSubContextView.js
deleted file mode 100644
index 5b313410c9a..00000000000
--- a/cocos2d/core/components/WXSubContextView.js
+++ /dev/null
@@ -1,136 +0,0 @@
-/****************************************************************************
- Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-const Component = require('./CCComponent');
-
-let WXSubContextView;
-
-if (!CC_EDITOR && !CC_WECHATGAME) {
- WXSubContextView = cc.Class({
- name: 'cc.WXSubContextView',
- extends: Component,
- })
-}
-else {
- /**
- * !#en WXSubContextView is a view component which controls open data context viewport in Wechat game platform.
- * The component's node size decide the viewport of the sub context content in main context,
- * the entire sub context texture will be scaled to the node's bounding box area.
- * This component provides multiple important features:
- * 1. Sub context could use its own resolution size and policy.
- * 2. Sub context could be minized to smallest size it needed.
- * 3. Resolution of sub context content could be increased.
- * 4. User touch input is transformed to the correct viewport.
- * 5. Texture update is handled by this component. User don't need to worry.
- * One important thing to be noted, whenever the node's bounding box change,
- * you need to manually reset the viewport of sub context using updateSubContextViewport.
- * !#zh WXSubContextView 可以用来控制微信小游戏平台开放数据域在主域中的视窗的位置。
- * 这个组件的节点尺寸决定了开放数据域内容在主域中的尺寸,整个开放数据域会被缩放到节点的包围盒范围内。
- * 在这个组件的控制下,用户可以更自由得控制开放数据域:
- * 1. 子域中可以使用独立的设计分辨率和适配模式
- * 2. 子域区域尺寸可以缩小到只容纳内容即可
- * 3. 子域的分辨率也可以被放大,以便获得更清晰的显示效果
- * 4. 用户输入坐标会被自动转换到正确的子域视窗中
- * 5. 子域内容贴图的更新由组件负责,用户不需要处理
- * 唯一需要注意的是,当子域节点的包围盒发生改变时,开发者需要使用 `updateSubContextViewport` 来手动更新子域视窗。
- * @class WXSubContextView
- * @extends Component
- */
- WXSubContextView = cc.Class({
- name: 'cc.WXSubContextView',
- extends: Component,
-
- editor: CC_EDITOR && {
- menu: 'i18n:MAIN_MENU.component.others/WXSubContextView',
- help: 'i18n:COMPONENT.help_url.wxSubContextView'
- },
-
- ctor () {
- this._sprite = null;
- this._tex = new cc.Texture2D();
- this._context = null;
- },
-
- onLoad () {
- // Setup subcontext canvas size
- if (wx.getOpenDataContext) {
- this._context = wx.getOpenDataContext();
- let sharedCanvas = this._context.canvas;
- if (sharedCanvas) {
- sharedCanvas.width = this.node.width;
- sharedCanvas.height = this.node.height;
- }
- this._tex.setPremultiplyAlpha(true);
- this._tex.initWithElement(sharedCanvas);
-
- this._sprite = this.node.getComponent(cc.Sprite);
- if (!this._sprite) {
- this._sprite = this.node.addComponent(cc.Sprite);
- this._sprite.srcBlendFactor = cc.macro.BlendFactor.ONE;
- }
- this._sprite.spriteFrame = new cc.SpriteFrame(this._tex);
- }
- else {
- this.enabled = false;
- }
- },
-
- onEnable () {
- this.updateSubContextViewport();
- },
-
- update () {
- if (!this._tex || !this._context) {
- return;
- }
- this._tex.initWithElement(this._context.canvas);
- this._sprite._activateMaterial();
- },
-
- /**
- * !#en Update the sub context viewport manually, it should be called whenever the node's bounding box changes.
- * !#zh 更新开放数据域相对于主域的 viewport,这个函数应该在节点包围盒改变时手动调用。
- * @method updateSubContextViewport
- */
- updateSubContextViewport () {
- if (this._context) {
- let box = this.node.getBoundingBoxToWorld();
- let sx = cc.view._scaleX;
- let sy = cc.view._scaleY;
- this._context.postMessage({
- fromEngine: true,
- event: 'viewport',
- x: box.x * sx + cc.view._viewportRect.x,
- y: box.y * sy + cc.view._viewportRect.y,
- width: box.width * sx,
- height: box.height * sy
- });
- }
- }
- });
-
-}
-
-cc.WXSubContextView = module.exports = WXSubContextView;
\ No newline at end of file
diff --git a/cocos2d/core/components/editbox/CCEditBox.js b/cocos2d/core/components/editbox/CCEditBox.js
index b6b5be0ffd9..b02596db8ed 100644
--- a/cocos2d/core/components/editbox/CCEditBox.js
+++ b/cocos2d/core/components/editbox/CCEditBox.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -25,15 +25,13 @@
****************************************************************************/
const macro = require('../../platform/CCMacro');
-const EditBoxImpl = require('../editbox/CCEditBoxImpl');
+const EditBoxImplBase = require('../editbox/EditBoxImplBase');
const Label = require('../CCLabel');
const Types = require('./types');
const InputMode = Types.InputMode;
const InputFlag = Types.InputFlag;
const KeyboardReturnType = Types.KeyboardReturnType;
-const LEFT_PADDING = 2;
-
function capitalize (string) {
return string.replace(/(?:^|\s)\S/g, function(a) { return a.toUpperCase(); });
}
@@ -61,7 +59,6 @@ let EditBox = cc.Class({
},
properties: {
- _useOriginalSize: true,
_string: '',
/**
* !#en Input string of EditBox.
@@ -74,29 +71,92 @@ let EditBox = cc.Class({
return this._string;
},
set(value) {
+ value = '' + value;
if (this.maxLength >= 0 && value.length >= this.maxLength) {
value = value.slice(0, this.maxLength);
}
this._string = value;
- if (this._impl) {
- this._updateString(value);
- }
+ this._updateString(value);
}
},
/**
- * !#en The background image of EditBox.
- * !#zh 输入框的背景图片
- * @property {SpriteFrame} backgroundImage
+ * !#en The Label component attached to the node for EditBox's input text label
+ * !#zh 输入框输入文本节点上挂载的 Label 组件对象
+ * @property {Label} textLabel
*/
- backgroundImage: {
- tooltip: CC_DEV && 'i18n:COMPONENT.editbox.backgroundImage',
+ textLabel: {
+ tooltip: CC_DEV && 'i18n:COMPONENT.editbox.textLabel',
default: null,
+ type: Label,
+ notify (oldValue) {
+ if (this.textLabel && this.textLabel !== oldValue) {
+ this._updateTextLabel();
+ this._updateLabels();
+ }
+ },
+ },
+
+ /**
+ * !#en The Label component attached to the node for EditBox's placeholder text label
+ * !#zh 输入框占位符节点上挂载的 Label 组件对象
+ * @property {Label} placeholderLabel
+ */
+ placeholderLabel: {
+ tooltip: CC_DEV && 'i18n:COMPONENT.editbox.placeholderLabel',
+ default: null,
+ type: Label,
+ notify (oldValue) {
+ if (this.placeholderLabel && this.placeholderLabel !== oldValue) {
+ this._updatePlaceholderLabel();
+ this._updateLabels();
+ }
+ },
+ },
+
+ /**
+ * !#en The Sprite component attached to the node for EditBox's background
+ * !#zh 输入框背景节点上挂载的 Sprite 组件对象
+ * @property {Sprite} background
+ */
+ background: {
+ tooltip: CC_DEV && 'i18n:COMPONENT.editbox.background',
+ default: null,
+ type: cc.Sprite,
+ notify (oldValue) {
+ if (this.background && this.background !== oldValue) {
+ this._updateBackgroundSprite();
+ }
+ },
+ },
+
+ // To be removed in the future
+ _N$backgroundImage: {
+ default: undefined,
type: cc.SpriteFrame,
- notify () {
- this._createBackgroundSprite();
- }
+ },
+
+ /**
+ * !#en The background image of EditBox. This property will be removed in the future, use editBox.background instead please.
+ * !#zh 输入框的背景图片。 该属性会在将来的版本中移除,请用 editBox.background
+ * @property {SpriteFrame} backgroundImage
+ * @deprecated since v2.1
+ */
+ backgroundImage: {
+ get () {
+ // if (!CC_EDITOR) cc.warnID(1400, 'editBox.backgroundImage', 'editBox.background');
+ if (!this.background) {
+ return null;
+ }
+ return this.background.spriteFrame;
+ },
+ set (value) {
+ // if (!CC_EDITOR) cc.warnID(1400, 'editBox.backgroundImage', 'editBox.background');
+ if (this.background) {
+ this.background.spriteFrame = value;
+ }
+ },
},
/**
@@ -114,11 +174,12 @@ let EditBox = cc.Class({
tooltip: CC_DEV && 'i18n:COMPONENT.editbox.returnType',
displayName: 'KeyboardReturnType',
type: KeyboardReturnType,
- notify () {
- if (this._impl) {
- this._impl.returnType = this.returnType;
- }
- }
+ },
+
+ // To be removed in the future
+ _N$returnType: {
+ default: undefined,
+ type: cc.Float,
},
/**
@@ -132,10 +193,7 @@ let EditBox = cc.Class({
default: InputFlag.DEFAULT,
type: InputFlag,
notify () {
- if (this._impl) {
- this._impl.setInputFlag(this.inputFlag);
- this._updateString(this._string);
- }
+ this._updateString(this._string);
}
},
/**
@@ -151,65 +209,96 @@ let EditBox = cc.Class({
tooltip: CC_DEV && 'i18n:COMPONENT.editbox.input_mode',
default: InputMode.ANY,
type: InputMode,
- notify () {
- if (this._impl) {
- this._impl.setInputMode(this.inputMode);
+ notify (oldValue) {
+ if (this.inputMode !== oldValue) {
+ this._updateTextLabel();
+ this._updatePlaceholderLabel();
}
}
},
/**
- * !#en Font size of the input text.
- * !#zh 输入框文本的字体大小
+ * !#en Font size of the input text. This property will be removed in the future, use editBox.textLabel.fontSize instead please.
+ * !#zh 输入框文本的字体大小。 该属性会在将来的版本中移除,请使用 editBox.textLabel.fontSize。
* @property {Number} fontSize
+ * @deprecated since v2.1
*/
fontSize: {
- tooltip: CC_DEV && 'i18n:COMPONENT.editbox.font_size',
- default: 20,
- notify () {
- if (this._textLabel) {
- this._textLabel.fontSize = this.fontSize;
+ get () {
+ // if (!CC_EDITOR) cc.warnID(1400, 'editBox.fontSize', 'editBox.textLabel.fontSize');
+ if (!this.textLabel) {
+ return 0;
}
- if (this._impl) {
- this._impl.setFontSize(this.fontSize);
+ return this.textLabel.fontSize;
+ },
+ set (value) {
+ // if (!CC_EDITOR) cc.warnID(1400, 'editBox.fontSize', 'editBox.textLabel.fontSize');
+ if (this.textLabel) {
+ this.textLabel.fontSize = value;
}
- }
+ },
+ },
+
+ // To be removed in the future
+ _N$fontSize: {
+ default: undefined,
+ type: cc.Float,
},
/**
- * !#en Change the lineHeight of displayed text.
- * !#zh 输入框文本的行高。
+ * !#en Change the lineHeight of displayed text. This property will be removed in the future, use editBox.textLabel.lineHeight instead.
+ * !#zh 输入框文本的行高。该属性会在将来的版本中移除,请使用 editBox.textLabel.lineHeight
* @property {Number} lineHeight
+ * @deprecated since v2.1
*/
lineHeight: {
- tooltip: CC_DEV && 'i18n:COMPONENT.editbox.line_height',
- default: 40,
- notify () {
- if (this._textLabel) {
- this._textLabel.lineHeight = this.lineHeight;
+ get () {
+ // if (!CC_EDITOR) cc.warnID(1400, 'editBox.lineHeight', 'editBox.textLabel.lineHeight');
+ if (!this.textLabel) {
+ return 0;
}
- }
+ return this.textLabel.lineHeight;
+ },
+ set (value) {
+ // if (!CC_EDITOR) cc.warnID(1400, 'editBox.lineHeight', 'editBox.textLabel.lineHeight');
+ if (this.textLabel) {
+ this.textLabel.lineHeight = value;
+ }
+ },
+ },
+
+ // To be removed in the future
+ _N$lineHeight: {
+ default: undefined,
+ type: cc.Float,
},
/**
- * !#en Font color of the input text.
- * !#zh 输入框文本的颜色。
+ * !#en Font color of the input text. This property will be removed in the future, use editBox.textLabel.node.color instead.
+ * !#zh 输入框文本的颜色。该属性会在将来的版本中移除,请使用 editBox.textLabel.node.color
* @property {Color} fontColor
+ * @deprecated since v2.1
*/
fontColor: {
- tooltip: CC_DEV && 'i18n:COMPONENT.editbox.font_color',
- default: cc.Color.WHITE,
- notify () {
- if (this._textLabel) {
- this._textLabel.node.opacity = this.fontColor.a;
- this._textLabel.node.color = this.fontColor;
+ get () {
+ // if (!CC_EDITOR) cc.warnID(1400, 'editBox.fontColor', 'editBox.textLabel.node.color');
+ if (!this.textLabel) {
+ return cc.Color.BLACK;
}
- if (this._impl) {
- this._impl.setFontColor(this.fontColor);
+ return this.textLabel.node.color;
+ },
+ set (value) {
+ // if (!CC_EDITOR) cc.warnID(1400, 'editBox.fontColor', 'editBox.textLabel.node.color');
+ if (this.textLabel) {
+ this.textLabel.node.color = value;
+ this.textLabel.node.opacity = value.a;
}
- }
+ },
},
+ // To be removed in the future
+ _N$fontColor: undefined,
+
/**
* !#en The display text of placeholder.
* !#zh 输入框占位符的文本内容。
@@ -217,48 +306,79 @@ let EditBox = cc.Class({
*/
placeholder: {
tooltip: CC_DEV && 'i18n:COMPONENT.editbox.placeholder',
- default: 'Enter text here...',
- notify () {
- if (this._placeholderLabel) {
- this._placeholderLabel.string = this.placeholder;
+ get () {
+ if (!this.placeholderLabel) {
+ return '';
}
- if (this._impl) {
- this._impl.setPlaceholderText(this.placeholder);
+ return this.placeholderLabel.string;
+ },
+ set (value) {
+ if (this.placeholderLabel) {
+ this.placeholderLabel.string = value;
}
}
},
+ // To be removed in the future
+ _N$placeholder: {
+ default: undefined,
+ type: cc.String,
+ },
+
/**
- * !#en The font size of placeholder.
- * !#zh 输入框占位符的字体大小。
+ * !#en The font size of placeholder. This property will be removed in the future, use editBox.placeholderLabel.fontSize instead.
+ * !#zh 输入框占位符的字体大小。该属性会在将来的版本中移除,请使用 editBox.placeholderLabel.fontSize
* @property {Number} placeholderFontSize
+ * @deprecated since v2.1
*/
placeholderFontSize: {
- tooltip: CC_DEV && 'i18n:COMPONENT.editbox.placeholder_font_size',
- default: 20,
- notify () {
- if (this._placeholderLabel) {
- this._placeholderLabel.fontSize = this.placeholderFontSize;
+ get () {
+ // if (!CC_EDITOR) cc.warnID(1400, 'editBox.placeholderFontSize', 'editBox.placeholderLabel.fontSize');
+ if (!this.placeholderLabel) {
+ return 0;
}
- }
+ return this.placeholderLabel.fontSize;
+ },
+ set (value) {
+ // if (!CC_EDITOR) cc.warnID(1400, 'editBox.placeholderFontSize', 'editBox.placeholderLabel.fontSize');
+ if (this.placeholderLabel) {
+ this.placeholderLabel.fontSize = value;
+ }
+ },
+ },
+
+ // To be removed in the future
+ _N$placeholderFontSize: {
+ default: undefined,
+ type: cc.Float,
},
/**
- * !#en The font color of placeholder.
- * !#zh 输入框占位符的字体颜色。
+ * !#en The font color of placeholder. This property will be removed in the future, use editBox.placeholderLabel.node.color instead.
+ * !#zh 输入框占位符的字体颜色。该属性会在将来的版本中移除,请使用 editBox.placeholderLabel.node.color
* @property {Color} placeholderFontColor
+ * @deprecated since v2.1
*/
placeholderFontColor: {
- tooltip: CC_DEV && 'i18n:COMPONENT.editbox.placeholder_font_color',
- default: cc.Color.GRAY,
- notify () {
- if (this._placeholderLabel) {
- this._placeholderLabel.node.color = this.placeholderFontColor;
- this._placeholderLabel.node.opacity = this.placeholderFontColor.a;
+ get () {
+ // if (!CC_EDITOR) cc.warnID(1400, 'editBox.placeholderFontColor', 'editBox.placeholderLabel.node.color');
+ if (!this.placeholderLabel) {
+ return cc.Color.BLACK;
}
- }
+ return this.placeholderLabel.node.color;
+ },
+ set (value) {
+ // if (!CC_EDITOR) cc.warnID(1400, 'editBox.placeholderFontColor', 'editBox.placeholderLabel.node.color');
+ if (this.placeholderLabel) {
+ this.placeholderLabel.node.color = value;
+ this.placeholderLabel.node.opacity = value.a;
+ }
+ },
},
+ // To be removed in the future
+ _N$placeholderFontColor: undefined,
+
/**
* !#en The maximize input length of EditBox.
* - If pass a value less than 0, it won't limit the input number of characters.
@@ -271,26 +391,25 @@ let EditBox = cc.Class({
maxLength: {
tooltip: CC_DEV && 'i18n:COMPONENT.editbox.max_length',
default: 20,
- notify () {
- if (this._impl) {
- this._impl.setMaxLength(this.maxLength);
- }
- }
+ },
+
+ // To be removed in the future
+ _N$maxLength: {
+ default: undefined,
+ type: cc.Float,
},
/**
- * !#en The input is always visible and be on top of the game view (only useful on Web).
- * !zh 输入框总是可见,并且永远在游戏视图的上面(这个属性只有在 Web 上面修改有意义)
+ * !#en The input is always visible and be on top of the game view (only useful on Web), this property will be removed on v2.1
+ * !zh 输入框总是可见,并且永远在游戏视图的上面(这个属性只有在 Web 上面修改有意义),该属性会在 v2.1 中移除
* Note: only available on Web at the moment.
* @property {Boolean} stayOnTop
+ * @deprecated since 2.0.8
*/
stayOnTop: {
- tooltip: CC_DEV && 'i18n:COMPONENT.editbox.stay_on_top',
default: false,
notify () {
- if (this._impl) {
- this._updateStayOnTop();
- }
+ cc.warn('editBox.stayOnTop is removed since v2.1.');
}
},
@@ -307,9 +426,11 @@ let EditBox = cc.Class({
return this._tabIndex;
},
set (value) {
- this._tabIndex = value;
- if (this._impl) {
- this._impl.setTabIndex(value);
+ if (this._tabIndex !== value) {
+ this._tabIndex = value;
+ if (this._impl) {
+ this._impl.setTabIndex(value);
+ }
}
}
},
@@ -357,86 +478,29 @@ let EditBox = cc.Class({
},
statics: {
- _EditBoxImpl: EditBoxImpl,
+ _ImplClass: EditBoxImplBase, // implemented on different platform adapter
KeyboardReturnType: KeyboardReturnType,
InputFlag: InputFlag,
InputMode: InputMode
},
_init () {
- this._createBackgroundSprite();
- this._createLabels();
- this.node.on(cc.Node.EventType.SIZE_CHANGED, this._resizeChildNodes, this);
-
- let impl = this._impl = new EditBoxImpl();
-
- impl.setDelegate(this);
- impl.setNode(this.node);
- impl.setInputMode(this.inputMode);
- impl.setMaxLength(this.maxLength);
- impl.setInputFlag(this.inputFlag);
- impl.setReturnType(this.returnType);
- impl.setTabIndex(this.tabIndex);
- impl.setFontColor(this.fontColor);
- impl.setFontSize(this.fontSize);
- impl.setPlaceholderText(this.placeholder);
-
- this._updateStayOnTop();
- this._updateString(this.string);
- this._syncSize();
- },
+ this._upgradeComp();
- _updateStayOnTop () {
- if (this.stayOnTop) {
- this._hideLabels();
- }
- else {
- this._showLabels();
- }
- this._impl.stayOnTop(this.stayOnTop);
- },
+ this._isLabelVisible = true;
+ this.node.on(cc.Node.EventType.SIZE_CHANGED, this._syncSize, this);
- _syncSize () {
- let size = this.node.getContentSize();
-
- this._background.node.setAnchorPoint(this.node.getAnchorPoint());
- this._background.node.setContentSize(size);
+ let impl = this._impl = new EditBox._ImplClass();
+ impl.init(this);
- this._updateLabelPosition(size);
- this._impl.setSize(size.width, size.height);
+ this._updateString(this._string);
+ this._syncSize();
},
- _updateLabelPosition (size) {
- let node = this.node;
- let offx = -node.anchorX * node.width;
- let offy = -node.anchorY * node.height;
-
- let placeholderLabel = this._placeholderLabel;
- let textLabel = this._textLabel;
-
- textLabel.node.setContentSize(size.width - LEFT_PADDING, size.height);
- placeholderLabel.node.setContentSize(size.width - LEFT_PADDING, size.height);
- placeholderLabel.lineHeight = size.height;
-
- placeholderLabel.node.setPosition(offx + LEFT_PADDING, offy + size.height);
- textLabel.node.setPosition(offx + LEFT_PADDING, offy + size.height);
+ _updateBackgroundSprite () {
+ let background = this.background;
- if (this.inputMode === InputMode.ANY){
- placeholderLabel.verticalAlign = macro.VerticalTextAlignment.TOP;
- placeholderLabel.enableWrapText = true;
- textLabel.verticalAlign = macro.VerticalTextAlignment.TOP;
- textLabel.enableWrapText = true;
- }
- else {
- placeholderLabel.verticalAlign = macro.VerticalTextAlignment.CENTER;
- placeholderLabel.enableWrapText = false;
- textLabel.verticalAlign = macro.VerticalTextAlignment.CENTER;
- textLabel.enableWrapText = false;
- }
- },
-
- _createBackgroundSprite () {
- let background = this._background;
+ // If background doesn't exist, create one.
if (!background) {
let node = this.node.getChildByName('BACKGROUND_SPRITE');
if (!node) {
@@ -447,86 +511,168 @@ let EditBox = cc.Class({
if (!background) {
background = node.addComponent(cc.Sprite);
}
- background.type = cc.Sprite.Type.SLICED;
-
node.parent = this.node;
- this._background = background;
+ this.background = background;
+ }
+
+ // update
+ background.type = cc.Sprite.Type.SLICED;
+
+ // handle old data
+ if (this._N$backgroundImage !== undefined) {
+ background.spriteFrame = this._N$backgroundImage;
+ this._N$backgroundImage = undefined;
}
- background.spriteFrame = this.backgroundImage;
},
- _createLabels () {
- if (!this._textLabel) {
+ _updateTextLabel () {
+ let textLabel = this.textLabel;
+
+ // If textLabel doesn't exist, create one.
+ if (!textLabel) {
let node = this.node.getChildByName('TEXT_LABEL');
if (!node) {
node = new cc.Node('TEXT_LABEL');
}
- node.color = this.fontColor;
- node.parent = this.node;
- node.setAnchorPoint(0, 1);
-
- let textLabel = node.getComponent(Label);
+ textLabel = node.getComponent(Label);
if (!textLabel) {
textLabel = node.addComponent(Label);
}
- textLabel.overflow = Label.Overflow.CLAMP;
- textLabel.fontSize = this.fontSize;
- textLabel.lineHeight = this.lineHeight;
- this._textLabel = textLabel;
+ node.parent = this.node;
+ this.textLabel = textLabel;
}
- if (!this._placeholderLabel) {
+ // update
+ textLabel.node.setAnchorPoint(0, 1);
+ textLabel.overflow = Label.Overflow.CLAMP;
+ if (this.inputMode === InputMode.ANY) {
+ textLabel.verticalAlign = macro.VerticalTextAlignment.TOP;
+ textLabel.enableWrapText = true;
+ }
+ else {
+ textLabel.verticalAlign = macro.VerticalTextAlignment.CENTER;
+ textLabel.enableWrapText = false;
+ }
+ textLabel.string = this._updateLabelStringStyle(this._string);
+
+ // handle old data
+ if (this._N$fontColor !== undefined) {
+ textLabel.node.color = this._N$fontColor;
+ textLabel.node.opacity = this._N$fontColor.a;
+ this._N$fontColor = undefined;
+ }
+ if (this._N$fontSize !== undefined) {
+ textLabel.fontSize = this._N$fontSize;
+ this._N$fontSize = undefined;
+ }
+ if (this._N$lineHeight !== undefined) {
+ textLabel.lineHeight = this._N$lineHeight;
+ this._N$lineHeight = undefined;
+ }
+ },
+
+ _updatePlaceholderLabel () {
+ let placeholderLabel = this.placeholderLabel;
+
+ // If placeholderLabel doesn't exist, create one.
+ if (!placeholderLabel) {
let node = this.node.getChildByName('PLACEHOLDER_LABEL');
if (!node) {
node = new cc.Node('PLACEHOLDER_LABEL');
}
- node.color = this.placeholderFontColor;
- node.parent = this.node;
- node.setAnchorPoint(0, 1);
-
- let placeholderLabel = node.getComponent(Label);
+ placeholderLabel = node.getComponent(Label);
if (!placeholderLabel) {
placeholderLabel = node.addComponent(Label);
}
- placeholderLabel.overflow = Label.Overflow.CLAMP;
- placeholderLabel.fontSize = this.placeholderFontSize;
- placeholderLabel.string = this.placeholder;
- this._placeholderLabel = placeholderLabel;
+ node.parent = this.node;
+ this.placeholderLabel = placeholderLabel;
+ }
+
+ // update
+ placeholderLabel.node.setAnchorPoint(0, 1);
+ placeholderLabel.overflow = Label.Overflow.CLAMP;
+ if (this.inputMode === InputMode.ANY) {
+ placeholderLabel.verticalAlign = macro.VerticalTextAlignment.TOP;
+ placeholderLabel.enableWrapText = true;
+ }
+ else {
+ placeholderLabel.verticalAlign = macro.VerticalTextAlignment.CENTER;
+ placeholderLabel.enableWrapText = false;
+ }
+ placeholderLabel.string = this.placeholder;
+
+ // handle old data
+ if (this._N$placeholderFontColor !== undefined) {
+ placeholderLabel.node.color = this._N$placeholderFontColor;
+ placeholderLabel.node.opacity = this._N$placeholderFontColor.a;
+ this._N$placeholderFontColor = undefined;
+ }
+ if (this._N$placeholderFontSize !== undefined) {
+ placeholderLabel.fontSize = this._N$placeholderFontSize;
+ this._N$placeholderFontSize = undefined;
}
},
- _resizeChildNodes () {
- let textLabelNode = this._textLabel.node,
- placeholderLabelNode = this._placeholderLabel.node,
- backgroundNode = this._background.node;
-
- textLabelNode.x = -this.node.width/2;
- textLabelNode.y = this.node.height/2;
- textLabelNode.width = this.node.width;
- textLabelNode.height = this.node.height;
-
- placeholderLabelNode.x = -this.node.width/2;
- placeholderLabelNode.y = this.node.height/2;
- placeholderLabelNode.width = this.node.width;
- placeholderLabelNode.height = this.node.height;
-
- backgroundNode.width = this.node.width;
- backgroundNode.height = this.node.height;
+ _upgradeComp () {
+ if (this._N$returnType !== undefined) {
+ this.returnType = this._N$returnType;
+ this._N$returnType = undefined;
+ }
+ if (this._N$maxLength !== undefined) {
+ this.maxLength = this._N$maxLength;
+ this._N$maxLength = undefined;
+ }
+ if (this._N$backgroundImage !== undefined) {
+ this._updateBackgroundSprite();
+ }
+ if (this._N$fontColor !== undefined || this._N$fontSize !== undefined || this._N$lineHeight !== undefined) {
+ this._updateTextLabel();
+ }
+ if (this._N$placeholderFontColor !== undefined || this._N$placeholderFontSize !== undefined) {
+ this._updatePlaceholderLabel();
+ }
+ if (this._N$placeholder !== undefined) {
+ this.placeholder = this._N$placeholder;
+ this._N$placeholder = undefined;
+ }
+ },
+
+ _syncSize () {
+ if (this._impl) {
+ let size = this.node.getContentSize();
+ this._impl.setSize(size.width, size.height);
+ }
},
_showLabels () {
- let displayText = this._textLabel.string;
- this._textLabel.node.active = displayText !== '';
- this._placeholderLabel.node.active = displayText === '';
+ this._isLabelVisible = true;
+ this._updateLabels();
},
_hideLabels () {
- this._textLabel.node.active = false;
- this._placeholderLabel.node.active = false;
+ this._isLabelVisible = false;
+ if (this.textLabel) {
+ this.textLabel.node.active = false;
+ }
+ if (this.placeholderLabel) {
+ this.placeholderLabel.node.active = false;
+ }
+ },
+
+ _updateLabels () {
+ if (this._isLabelVisible) {
+ let content = this._string;
+ if (this.textLabel) {
+ this.textLabel.node.active = (content !== '');
+ }
+ if (this.placeholderLabel) {
+ this.placeholderLabel.node.active = (content === '');
+ }
+ }
},
_updateString (text) {
- let textLabel = this._textLabel;
+ let textLabel = this.textLabel;
// Not inited yet
if (!textLabel) {
return;
@@ -538,10 +684,8 @@ let EditBox = cc.Class({
}
textLabel.string = displayText;
- this._impl.setString(text);
- if (!this._impl._editing && !this.stayOnTop) {
- this._showLabels();
- }
+
+ this._updateLabels();
},
_updateLabelStringStyle (text, ignorePassword) {
@@ -568,15 +712,11 @@ let EditBox = cc.Class({
},
editBoxEditingDidBegan () {
- this._hideLabels();
cc.Component.EventHandler.emitEvents(this.editingDidBegan, this);
this.node.emit('editing-did-began', this);
},
editBoxEditingDidEnded () {
- if (!this.stayOnTop) {
- this._showLabels();
- }
cc.Component.EventHandler.emitEvents(this.editingDidEnded, this);
this.node.emit('editing-did-ended', this);
},
@@ -593,22 +733,31 @@ let EditBox = cc.Class({
this.node.emit('editing-return', this);
},
- onDestroy () {
- this._impl.clear();
- },
-
onEnable () {
- this._impl && this._impl.onEnable();
+ if (!CC_EDITOR) {
+ this._registerEvent();
+ }
+ if (this._impl) {
+ this._impl.enable();
+ }
},
onDisable () {
- this._impl && this._impl.onDisable();
+ if (!CC_EDITOR) {
+ this._unregisterEvent();
+ }
+ if (this._impl) {
+ this._impl.disable();
+ }
},
- __preload () {
- if (!CC_EDITOR) {
- this._registerEvent();
+ onDestroy () {
+ if (this._impl) {
+ this._impl.clear();
}
+ },
+
+ __preload () {
this._init();
},
@@ -617,50 +766,73 @@ let EditBox = cc.Class({
this.node.on(cc.Node.EventType.TOUCH_END, this._onTouchEnded, this);
},
+ _unregisterEvent () {
+ this.node.off(cc.Node.EventType.TOUCH_START, this._onTouchBegan, this);
+ this.node.off(cc.Node.EventType.TOUCH_END, this._onTouchEnded, this);
+ },
+
_onTouchBegan (event) {
- if (this._impl) {
- this._impl._onTouchBegan(event.touch);
- }
event.stopPropagation();
},
_onTouchCancel (event) {
- if (this._impl) {
- this._impl._onTouchCancel();
- }
event.stopPropagation();
},
_onTouchEnded (event) {
if (this._impl) {
- this._impl._onTouchEnded();
+ this._impl.beginEditing();
}
event.stopPropagation();
},
/**
- * !#en Let the EditBox get focus
- * !#zh 让当前 EditBox 获得焦点
+ * !#en Let the EditBox get focus, this method will be removed on v2.1
+ * !#zh 让当前 EditBox 获得焦点, 这个方法会在 v2.1 中移除
* @method setFocus
+ * @deprecated since 2.0.8
*/
setFocus () {
- if(this._impl) {
- this._impl.setFocus();
+ cc.errorID(1400, 'setFocus()', 'focus()');
+ if (this._impl) {
+ this._impl.setFocus(true);
+ }
+ },
+
+ /**
+ * !#en Let the EditBox get focus
+ * !#zh 让当前 EditBox 获得焦点
+ * @method focus
+ */
+ focus () {
+ if (this._impl) {
+ this._impl.setFocus(true);
+ }
+ },
+
+ /**
+ * !#en Let the EditBox lose focus
+ * !#zh 让当前 EditBox 失去焦点
+ * @method blur
+ */
+ blur () {
+ if (this._impl) {
+ this._impl.setFocus(false);
}
},
/**
* !#en Determine whether EditBox is getting focus or not.
* !#zh 判断 EditBox 是否获得了焦点
- * Note: only available on Web at the moment.
* @method isFocused
*/
isFocused () {
- let isFocused = false;
if (this._impl) {
- isFocused = this._impl.isFocused();
+ return this._impl.isFocused();
+ }
+ else {
+ return false;
}
- return isFocused;
},
update () {
@@ -673,6 +845,10 @@ let EditBox = cc.Class({
cc.EditBox = module.exports = EditBox;
+if (cc.sys.isBrowser) {
+ require('./WebEditBoxImpl');
+}
+
/**
* !#en
* Note: This event is emitted from the node to which the component belongs.
@@ -726,4 +902,4 @@ cc.EditBox = module.exports = EditBox;
* editbox.node.destroy();
* @method destroy
* @return {Boolean} whether it is the first time the destroy being called
- */
+ */
\ No newline at end of file
diff --git a/cocos2d/core/components/editbox/CCEditBoxImpl.js b/cocos2d/core/components/editbox/CCEditBoxImpl.js
deleted file mode 100644
index f198c565d79..00000000000
--- a/cocos2d/core/components/editbox/CCEditBoxImpl.js
+++ /dev/null
@@ -1,648 +0,0 @@
-/****************************************************************************
- Copyright (c) 2011-2012 cocos2d-x.org
- Copyright (c) 2012 James Chen
- Copyright (c) 2013-2016 Chukong Technologies Inc.
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-const utils = require('../../platform/utils');
-const macro = require('../../platform/CCMacro');
-const Types = require('./types');
-const InputMode = Types.InputMode;
-const InputFlag = Types.InputFlag;
-const KeyboardReturnType = Types.KeyboardReturnType;
-
-// https://segmentfault.com/q/1010000002914610
-let SCROLLY = 40;
-let LEFT_PADDING = 2;
-let DELAY_TIME = 400;
-let FOCUS_DELAY_UC = 400;
-let FOCUS_DELAY_FIREFOX = 0;
-
-let math = cc.vmath;
-let _matrix = math.mat4.create();
-let _matrix_temp = math.mat4.create();
-let _vec3 = cc.v3();
-
-let _currentEditBoxImpl = null;
-
-// polyfill
-let polyfill = {
- zoomInvalid: false
-};
-
-if (cc.sys.OS_ANDROID === cc.sys.os &&
- (cc.sys.browserType === cc.sys.BROWSER_TYPE_SOUGOU ||
- cc.sys.browserType === cc.sys.BROWSER_TYPE_360)) {
- polyfill.zoomInvalid = true;
-}
-
-function getKeyboardReturnType (type) {
- switch (type) {
- case KeyboardReturnType.DEFAULT:
- case KeyboardReturnType.DONE:
- return 'done';
- case KeyboardReturnType.SEND:
- return 'send';
- case KeyboardReturnType.SEARCH:
- return 'search';
- case KeyboardReturnType.GO:
- return 'go';
- case KeyboardReturnType.NEXT:
- return 'next';
- }
- return 'done';
-}
-
-let EditBoxImpl = cc.Class({
- ctor () {
- this._delegate = null;
- this._inputMode = -1;
- this._inputFlag = -1;
- this._returnType = KeyboardReturnType.DEFAULT;
- this._maxLength = 50;
- this._text = '';
- this._placeholderText = '';
- this._alwaysOnTop = false;
- this._size = cc.size();
- this._node = null;
- this._editing = false;
-
- this.__eventListeners = {};
- this.__fullscreen = false;
- this.__autoResize = false;
- this.__rotateScreen = false;
- this.__orientationChanged = null;
- },
-
- onEnable () {
- if (!this._edTxt) {
- return;
- }
- if (this._alwaysOnTop) {
- this._edTxt.style.display = '';
- }
- else {
- this._edTxt.style.display = 'none';
- }
- },
-
- onDisable () {
- if (!this._edTxt) {
- return;
- }
- this._edTxt.style.display = 'none';
- },
-
- setTabIndex (index) {
- if (this._edTxt) {
- this._edTxt.tabIndex = index;
- }
- },
-
- setFocus () {
- this._beginEditing();
- },
-
- isFocused() {
- if (this._edTxt) {
- return document.activeElement === this._edTxt;
- }
- cc.warnID(4700);
- return false;
- },
-
- stayOnTop (flag) {
- if(this._alwaysOnTop === flag || !this._edTxt) return;
-
- this._alwaysOnTop = flag;
-
- if (flag) {
- this._edTxt.style.display = '';
- } else {
- this._edTxt.style.display = 'none';
- }
- },
-
- setMaxLength (maxLength) {
- if (!isNaN(maxLength)) {
- if(maxLength < 0) {
- //we can't set Number.MAX_VALUE to input's maxLength property
- //so we use a magic number here, it should works at most use cases.
- maxLength = 65535;
- }
- this._maxLength = maxLength;
- this._edTxt && (this._edTxt.maxLength = maxLength);
- }
- },
-
- setString (text) {
- this._text = text;
- this._edTxt && (this._edTxt.value = text);
- },
-
- getString () {
- return this._text;
- },
-
- setPlaceholderText (text) {
- this._placeholderText = text;
- },
-
- getPlaceholderText () {
- return this._placeholderText;
- },
-
- setDelegate (delegate) {
- this._delegate = delegate;
- },
-
- setInputMode (inputMode) {
- if (this._inputMode === inputMode) return;
-
- this._inputMode = inputMode;
- this.createInput();
-
- this._updateDomInputType();
- this._updateSize(this._size.width, this._size.height);
- },
-
- setInputFlag (inputFlag) {
- if (this._inputFlag === inputFlag) return;
-
- this._inputFlag = inputFlag;
- this._updateDomInputType();
-
- let textTransform = 'none';
-
- if (inputFlag === InputFlag.INITIAL_CAPS_ALL_CHARACTERS) {
- textTransform = 'uppercase';
- }
- else if (inputFlag === InputFlag.INITIAL_CAPS_WORD) {
- textTransform = 'capitalize';
- }
-
- if (this._edTxt) {
- this._edTxt.style.textTransform = textTransform;
- this._edTxt.value = this._text;
- }
- },
-
- setReturnType (returnType) {
- this._returnType = returnType;
- this._updateDomInputType();
- },
-
- setFontSize (fontSize) {
- this._edFontSize = fontSize || this._edFontSize;
- this._edTxt && (this._edTxt.style.fontSize = this._edFontSize + 'px');
- },
-
- setFontColor (color) {
- this._textColor = color;
- this._edTxt && (this._edTxt.style.color = color.toCSS('rgba'));
- },
-
- setSize (width, height) {
- this._size.width = width;
- this._size.height = height;
- this._updateSize(width, height);
- },
-
- setNode (node) {
- this._node = node;
- },
-
- update () {
- // TODO: find better way to update matrix
- // if (this._editing) {
- this._updateMatrix();
- // }
- },
-
- clear () {
- this._node = null;
- this.setDelegate(null);
- this.removeDom();
- },
-
- _onTouchBegan (touch) {
-
- },
-
- _onTouchEnded () {
- this._beginEditing();
- },
-
- _beginEditing () {
- if (cc.sys.isMobile && !this._editing) {
- // Pre adaptation
- this._beginEditingOnMobile();
- }
-
- if (this._edTxt) {
- this._edTxt.style.display = '';
-
- let self = this;
- function startFocus () {
- self._edTxt.focus();
- }
-
- if (cc.sys.browserType === cc.sys.BROWSER_TYPE_UC) {
- setTimeout(startFocus, FOCUS_DELAY_UC);
- }
- else if (cc.sys.browserType === cc.sys.BROWSER_TYPE_FIREFOX) {
- setTimeout(startFocus, FOCUS_DELAY_FIREFOX);
- }
- else {
- startFocus();
- }
- }
-
- this._editing = true;
- },
-
- _endEditing () {
- let self = this;
- let hideDomInputAndShowLabel = function () {
- if (!self._alwaysOnTop && self._edTxt) {
- self._edTxt.style.display = 'none';
- }
- if (self._delegate && self._delegate.editBoxEditingDidEnded) {
- self._delegate.editBoxEditingDidEnded();
- }
- };
- if (this._editing) {
- if (cc.sys.isMobile) {
- // Delay end editing adaptation to ensure virtual keyboard is disapeared
- setTimeout(function () {
- self._endEditingOnMobile();
- hideDomInputAndShowLabel();
- }, DELAY_TIME);
- }
- else {
- hideDomInputAndShowLabel();
- }
- }
- this._editing = false;
- },
-
- _updateDomInputType () {
- let inputMode = this._inputMode;
- let edTxt = this._edTxt;
- if (!edTxt) return;
-
- if (this._inputFlag === InputFlag.PASSWORD) {
- edTxt.type = 'password';
- return;
- }
-
- let type = edTxt.type;
- if (inputMode === InputMode.EMAIL_ADDR) {
- type = 'email';
- } else if(inputMode === InputMode.NUMERIC || inputMode === InputMode.DECIMAL) {
- type = 'number';
- } else if(inputMode === InputMode.PHONE_NUMBER) {
- type = 'number';
- edTxt.pattern = '[0-9]*';
- } else if(inputMode === InputMode.URL) {
- type = 'url';
- } else {
- type = 'text';
-
- if (this._returnType === KeyboardReturnType.SEARCH) {
- type = 'search';
- }
- }
-
- edTxt.type = type;
- },
-
- _updateSize (newWidth, newHeight) {
- let edTxt = this._edTxt;
- if (!edTxt) return;
-
- edTxt.style.width = newWidth + 'px';
- edTxt.style.height = newHeight + 'px';
- },
-
- _updateMatrix () {
- if (!this._edTxt) return;
-
- let node = this._node,
- scaleX = cc.view._scaleX, scaleY = cc.view._scaleY,
- viewport = cc.view._viewportRect,
- dpr = cc.view._devicePixelRatio;
-
- node.getWorldMatrix(_matrix);
- let contentSize = node._contentSize;
- _vec3.x = -node._anchorPoint.x * contentSize.width;
- _vec3.y = -node._anchorPoint.y * contentSize.height;
-
- math.mat4.translate(_matrix, _matrix, _vec3);
-
- let camera;
- // can't find camera in editor
- if (CC_EDITOR) {
- camera = cc.Camera.main;
- }
- else {
- camera = cc.Camera.findCamera(node);
- }
-
- camera.getWorldToCameraMatrix(_matrix_temp);
- math.mat4.mul(_matrix_temp, _matrix_temp, _matrix);
-
- scaleX /= dpr;
- scaleY /= dpr;
-
- let container = cc.game.container;
- let a = _matrix_temp.m00 * scaleX, b = _matrix.m01, c = _matrix.m04, d = _matrix_temp.m05 * scaleY;
-
- let offsetX = container && container.style.paddingLeft && parseInt(container.style.paddingLeft);
- offsetX += viewport.x / dpr;
- let offsetY = container && container.style.paddingBottom && parseInt(container.style.paddingBottom);
- offsetY += viewport.y / dpr;
- let tx = _matrix_temp.m12 * scaleX + offsetX, ty = _matrix_temp.m13 * scaleY + offsetY;
-
- if (polyfill.zoomInvalid) {
- this._updateSize(this._size.width * a, this._size.height * d);
- a = 1;
- d = 1;
- }
-
- let matrix = "matrix(" + a + "," + -b + "," + -c + "," + d + "," + tx + "," + -ty + ")";
- this._edTxt.style['transform'] = matrix;
- this._edTxt.style['-webkit-transform'] = matrix;
- this._edTxt.style['transform-origin'] = '0px 100% 0px';
- this._edTxt.style['-webkit-transform-origin'] = '0px 100% 0px';
- },
-
- _adjustEditBoxPosition () {
- this._node.getWorldMatrix(_matrix);
- let y = _matrix.m13;
- let windowHeight = cc.visibleRect.height;
- let windowWidth = cc.visibleRect.width;
- let factor = 0.5;
- if (windowWidth > windowHeight) {
- factor = 0.7;
- }
- setTimeout(function() {
- if (window.scrollY < SCROLLY && y < windowHeight * factor) {
- let scrollOffset = windowHeight * factor - y - window.scrollY;
- if (scrollOffset < 35) scrollOffset = 35;
- if (scrollOffset > 320) scrollOffset = 320;
- window.scrollTo(0, scrollOffset);
- }
- }, DELAY_TIME);
- }
-});
-
-let _p = EditBoxImpl.prototype;
-
-_p.createInput = function() {
- if (this._inputMode === InputMode.ANY) {
- this._createDomTextArea();
- }
- else {
- this._createDomInput();
- }
-};
-
-// Called before editbox focus to register cc.view status
-_p._beginEditingOnMobile = function () {
- let self = this;
- this.__orientationChanged = function () {
- self._adjustEditBoxPosition();
- };
- window.addEventListener('orientationchange', this.__orientationChanged);
-
- if (cc.view.isAutoFullScreenEnabled()) {
- this.__fullscreen = true;
- cc.view.enableAutoFullScreen(false);
- cc.screen.exitFullScreen();
- } else {
- this.__fullscreen = false;
- }
- this.__autoResize = cc.view._resizeWithBrowserSize;
- cc.view.resizeWithBrowserSize(false);
- _currentEditBoxImpl = this;
-};
-
-// Called after keyboard disappeared to readapte the game view
-_p._endEditingOnMobile = function () {
- if (this.__rotateScreen) {
- cc.game.container.style['-webkit-transform'] = 'rotate(90deg)';
- cc.game.container.style.transform = 'rotate(90deg)';
-
- let view = cc.view;
- let width = view._originalDesignResolutionSize.width;
- let height = view._originalDesignResolutionSize.height;
- if (width > 0) {
- view.setDesignResolutionSize(width, height, view._resolutionPolicy);
- }
- this.__rotateScreen = false;
- }
-
- window.removeEventListener('orientationchange', this.__orientationChanged);
-
- if(this.__fullscreen) {
- cc.view.enableAutoFullScreen(true);
- }
-
- // In case focus on editBox A from editBox B
- // A disable resizeWithBrowserSize
- // whilte B enable resizeWithBrowserSize
- // Only _currentEditBoxImpl can enable resizeWithBrowserSize
- if (this.__autoResize && _currentEditBoxImpl === this) {
- cc.view.resizeWithBrowserSize(true);
- }
-};
-
-function _inputValueHandle (input, editBoxImpl) {
- if (input.value.length > editBoxImpl._maxLength) {
- input.value = input.value.slice(0, editBoxImpl._maxLength);
- }
- if (editBoxImpl._delegate && editBoxImpl._delegate.editBoxTextChanged) {
- if (editBoxImpl._text !== input.value) {
- editBoxImpl._text = input.value;
- editBoxImpl._delegate.editBoxTextChanged(editBoxImpl._text);
- }
- }
-}
-
-function registerInputEventListener (tmpEdTxt, editBoxImpl, isTextarea) {
- let inputLock = false;
- let cbs = editBoxImpl.__eventListeners;
- cbs.compositionstart = function () {
- inputLock = true;
- };
- tmpEdTxt.addEventListener('compositionstart', cbs.compositionstart);
-
- cbs.compositionend = function () {
- inputLock = false;
- _inputValueHandle(this, editBoxImpl);
- };
- tmpEdTxt.addEventListener('compositionend', cbs.compositionend);
-
- cbs.input = function () {
- if (inputLock) {
- return;
- }
- _inputValueHandle(this, editBoxImpl);
- };
- tmpEdTxt.addEventListener('input', cbs.input);
-
- cbs.focus = function () {
- this.style.fontSize = editBoxImpl._edFontSize + 'px';
- this.style.color = editBoxImpl._textColor.toCSS('rgba');
- // When stayOnTop, input will swallow touch event
- if (editBoxImpl._alwaysOnTop) {
- editBoxImpl._editing = true;
- }
-
- if (cc.sys.isMobile) {
- editBoxImpl._beginEditingOnMobile();
- }
-
- if (editBoxImpl._delegate && editBoxImpl._delegate.editBoxEditingDidBegan) {
- editBoxImpl._delegate.editBoxEditingDidBegan();
- }
-
- };
- tmpEdTxt.addEventListener('focus', cbs.focus);
-
- cbs.keypress = function (e) {
- if (e.keyCode === macro.KEY.enter) {
- e.stopPropagation();
-
- if (editBoxImpl._delegate && editBoxImpl._delegate.editBoxEditingReturn) {
- editBoxImpl._delegate.editBoxEditingReturn();
- }
- if (!isTextarea) {
- editBoxImpl._text = this.value;
- editBoxImpl._endEditing();
- cc.game.canvas.focus();
- }
- }
- };
- tmpEdTxt.addEventListener('keypress', cbs.keypress);
-
- cbs.blur = function () {
- editBoxImpl._text = this.value;
- editBoxImpl._endEditing();
- };
- tmpEdTxt.addEventListener('blur', cbs.blur);
-
- editBoxImpl._addDomToGameContainer();
-}
-
-_p._createDomInput = function () {
- this.removeDom();
-
- let tmpEdTxt = this._edTxt = document.createElement('input');
- tmpEdTxt.type = 'text';
- tmpEdTxt.style.fontSize = this._edFontSize + 'px';
- tmpEdTxt.style.color = '#000000';
- tmpEdTxt.style.border = 0;
- tmpEdTxt.style.background = 'transparent';
- tmpEdTxt.style.width = '100%';
- tmpEdTxt.style.height = '100%';
- tmpEdTxt.style.active = 0;
- tmpEdTxt.style.outline = 'medium';
- tmpEdTxt.style.padding = '0';
- tmpEdTxt.style.textTransform = 'uppercase';
- tmpEdTxt.style.display = 'none';
- tmpEdTxt.style.position = "absolute";
- tmpEdTxt.style.bottom = "0px";
- tmpEdTxt.style.left = LEFT_PADDING + "px";
- tmpEdTxt.style['-moz-appearance'] = 'textfield';
- tmpEdTxt.style.className = "cocosEditBox";
- tmpEdTxt.style.fontFamily = 'Arial';
-
- registerInputEventListener(tmpEdTxt, this);
-
- return tmpEdTxt;
-};
-
-_p._createDomTextArea = function () {
- this.removeDom();
-
- let tmpEdTxt = this._edTxt = document.createElement('textarea');
- tmpEdTxt.type = 'text';
- tmpEdTxt.style.fontSize = this._edFontSize + 'px';
- tmpEdTxt.style.color = '#000000';
- tmpEdTxt.style.border = 0;
- tmpEdTxt.style.background = 'transparent';
- tmpEdTxt.style.width = '100%';
- tmpEdTxt.style.height = '100%';
- tmpEdTxt.style.active = 0;
- tmpEdTxt.style.outline = 'medium';
- tmpEdTxt.style.padding = '0';
- tmpEdTxt.style.resize = 'none';
- tmpEdTxt.style.textTransform = 'uppercase';
- tmpEdTxt.style.overflow_y = 'scroll';
- tmpEdTxt.style.display = 'none';
- tmpEdTxt.style.position = "absolute";
- tmpEdTxt.style.bottom = "0px";
- tmpEdTxt.style.left = LEFT_PADDING + "px";
- tmpEdTxt.style.className = "cocosEditBox";
- tmpEdTxt.style.fontFamily = 'Arial';
-
- registerInputEventListener(tmpEdTxt, this, true);
-
- return tmpEdTxt;
-};
-
-_p._addDomToGameContainer = function () {
- cc.game.container.appendChild(this._edTxt);
-};
-
-_p.removeDom = function () {
- let edTxt = this._edTxt;
- if (edTxt) {
- // Remove listeners
- let cbs = this.__eventListeners;
- edTxt.removeEventListener('compositionstart', cbs.compositionstart);
- edTxt.removeEventListener('compositionend', cbs.compositionend);
- edTxt.removeEventListener('input', cbs.input);
- edTxt.removeEventListener('focus', cbs.focus);
- edTxt.removeEventListener('keypress', cbs.keypress);
- edTxt.removeEventListener('blur', cbs.blur);
- cbs.compositionstart = null;
- cbs.compositionend = null;
- cbs.input = null;
- cbs.focus = null;
- cbs.keypress = null;
- cbs.blur = null;
-
- let hasChild = utils.contains(cc.game.container, edTxt);
- if (hasChild) {
- cc.game.container.removeChild(edTxt);
- }
- }
- this._edTxt = null;
-};
-
-module.exports = EditBoxImpl;
diff --git a/cocos2d/core/load-pipeline/text-downloader.js b/cocos2d/core/components/editbox/EditBoxImplBase.js
similarity index 57%
rename from cocos2d/core/load-pipeline/text-downloader.js
rename to cocos2d/core/components/editbox/EditBoxImplBase.js
index a64ca7f740f..8b1f65f34cf 100644
--- a/cocos2d/core/load-pipeline/text-downloader.js
+++ b/cocos2d/core/components/editbox/EditBoxImplBase.js
@@ -1,7 +1,10 @@
/****************************************************************************
+ Copyright (c) 2011-2012 cocos2d-x.org
+ Copyright (c) 2012 James Chen
+ Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -23,34 +26,62 @@
THE SOFTWARE.
****************************************************************************/
-var urlAppendTimestamp = require('./utils').urlAppendTimestamp;
-
-module.exports = function (item, callback) {
- var url = item.url;
- url = urlAppendTimestamp(url);
-
- var xhr = cc.loader.getXMLHttpRequest(),
- errInfo = 'Load text file failed: ' + url;
- xhr.open('GET', url, true);
- if (xhr.overrideMimeType) xhr.overrideMimeType('text\/plain; charset=utf-8');
- xhr.onload = function () {
- if (xhr.readyState === 4) {
- if (xhr.status === 200 || xhr.status === 0) {
- callback(null, xhr.responseText);
- }
- else {
- callback({status:xhr.status, errorMessage:errInfo + '(wrong status)'});
- }
+let EditBoxImplBase = cc.Class({
+ ctor () {
+ this._delegate = null;
+ this._editing = false;
+ },
+
+ init (delegate) {
+
+ },
+
+ enable () {
+
+ },
+
+ disable () {
+ if (this._editing) {
+ this.endEditing();
+ }
+ },
+
+ clear () {
+
+ },
+
+ update () {
+
+ },
+
+ setTabIndex (index) {
+
+ },
+
+ setSize (width, height) {
+
+ },
+
+ setFocus (value) {
+ if (value) {
+ this.beginEditing();
}
else {
- callback({status:xhr.status, errorMessage:errInfo + '(wrong readyState)'});
+ this.endEditing();
}
- };
- xhr.onerror = function(){
- callback({status:xhr.status, errorMessage:errInfo + '(error)'});
- };
- xhr.ontimeout = function(){
- callback({status:xhr.status, errorMessage:errInfo + '(time out)'});
- };
- xhr.send(null);
-};
\ No newline at end of file
+ },
+
+ isFocused () {
+ return this._editing;
+ },
+
+ beginEditing () {
+
+ },
+
+ endEditing () {
+
+ },
+});
+
+module.exports = EditBoxImplBase;
diff --git a/cocos2d/core/components/editbox/WebEditBoxImpl.js b/cocos2d/core/components/editbox/WebEditBoxImpl.js
new file mode 100644
index 00000000000..b1199eaad51
--- /dev/null
+++ b/cocos2d/core/components/editbox/WebEditBoxImpl.js
@@ -0,0 +1,721 @@
+/****************************************************************************
+ Copyright (c) 2013-2016 Chukong Technologies Inc.
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import Mat4 from '../../value-types/mat4';
+
+const utils = require('../../platform/utils');
+const macro = require('../../platform/CCMacro');
+const Types = require('./types');
+const Label = require('../CCLabel');
+const tabIndexUtil = require('./tabIndexUtil');
+
+const EditBox = cc.EditBox;
+const js = cc.js;
+const InputMode = Types.InputMode;
+const InputFlag = Types.InputFlag;
+const KeyboardReturnType = Types.KeyboardReturnType;
+
+// polyfill
+let polyfill = {
+ zoomInvalid: false
+};
+
+if (cc.sys.OS_ANDROID === cc.sys.os &&
+ (cc.sys.browserType === cc.sys.BROWSER_TYPE_SOUGOU ||
+ cc.sys.browserType === cc.sys.BROWSER_TYPE_360)) {
+ polyfill.zoomInvalid = true;
+}
+
+// https://segmentfault.com/q/1010000002914610
+const DELAY_TIME = 800;
+const SCROLLY = 100;
+const LEFT_PADDING = 2;
+
+// private static property
+let _domCount = 0;
+let _vec3 = cc.v3();
+let _currentEditBoxImpl = null;
+
+// on mobile
+let _fullscreen = false;
+let _autoResize = false;
+
+const BaseClass = EditBox._ImplClass;
+ // This is an adapter for EditBoxImpl on web platform.
+ // For more adapters on other platforms, please inherit from EditBoxImplBase and implement the interface.
+function WebEditBoxImpl () {
+ BaseClass.call(this);
+ this._domId = `EditBoxId_${++_domCount}`;
+ this._placeholderStyleSheet = null;
+ this._elem = null;
+ this._isTextArea = false;
+
+ // matrix
+ this._worldMat = new Mat4();
+ this._cameraMat = new Mat4();
+ // matrix cache
+ this._m00 = 0;
+ this._m01 = 0;
+ this._m04 = 0;
+ this._m05 = 0;
+ this._m12 = 0;
+ this._m13 = 0;
+ this._w = 0;
+ this._h = 0;
+ // viewport cache
+ this._cacheViewportRect = cc.rect(0, 0, 0, 0);
+
+ // inputType cache
+ this._inputMode = null;
+ this._inputFlag = null;
+ this._returnType = null;
+
+ // event listeners
+ this._eventListeners = {};
+
+ // update style sheet cache
+ this._textLabelFont = null;
+ this._textLabelFontSize = null;
+ this._textLabelFontColor = null;
+ this._textLabelAlign = null;
+
+ this._placeholderLabelFont = null;
+ this._placeholderLabelFontSize = null;
+ this._placeholderLabelFontColor = null;
+ this._placeholderLabelAlign = null;
+ this._placeholderLineHeight = null;
+}
+
+js.extend(WebEditBoxImpl, BaseClass);
+EditBox._ImplClass = WebEditBoxImpl;
+
+Object.assign(WebEditBoxImpl.prototype, {
+ // =================================
+ // implement EditBoxImplBase interface
+ init (delegate) {
+ if (!delegate) {
+ return;
+ }
+
+ this._delegate = delegate;
+
+ if (delegate.inputMode === InputMode.ANY) {
+ this._createTextArea();
+ }
+ else {
+ this._createInput();
+ }
+ tabIndexUtil.add(this);
+ this.setTabIndex(delegate.tabIndex);
+ this._initStyleSheet();
+ this._registerEventListeners();
+ this._addDomToGameContainer();
+
+ _fullscreen = cc.view.isAutoFullScreenEnabled();
+ _autoResize = cc.view._resizeWithBrowserSize;
+ },
+
+ clear () {
+ this._removeEventListeners();
+ this._removeDomFromGameContainer();
+
+ tabIndexUtil.remove(this);
+
+ // clear while editing
+ if (_currentEditBoxImpl === this) {
+ _currentEditBoxImpl = null;
+ }
+ },
+
+ update () {
+ this._updateMatrix();
+ },
+
+ setTabIndex (index) {
+ this._elem.tabIndex = index;
+ tabIndexUtil.resort();
+ },
+
+ setSize (width, height) {
+ let elem = this._elem;
+ elem.style.width = width + 'px';
+ elem.style.height = height + 'px';
+ },
+
+ beginEditing () {
+ if (_currentEditBoxImpl && _currentEditBoxImpl !== this) {
+ _currentEditBoxImpl.setFocus(false);
+ }
+ this._editing = true;
+ _currentEditBoxImpl = this;
+ this._delegate.editBoxEditingDidBegan();
+ this._showDom();
+ this._elem.focus(); // set focus
+ },
+
+ endEditing () {
+ if (this._elem) {
+ this._elem.blur();
+ }
+ },
+
+ // ==========================================================================
+ // implement dom input
+ _createInput () {
+ this._isTextArea = false;
+ this._elem = document.createElement('input');
+ },
+
+ _createTextArea () {
+ this._isTextArea = true;
+ this._elem = document.createElement('textarea');
+ },
+
+ _addDomToGameContainer () {
+ cc.game.container.appendChild(this._elem);
+ document.head.appendChild(this._placeholderStyleSheet);
+ },
+
+ _removeDomFromGameContainer () {
+ let hasElem = utils.contains(cc.game.container, this._elem);
+ if (hasElem) {
+ cc.game.container.removeChild(this._elem);
+ }
+ let hasStyleSheet = utils.contains(document.head, this._placeholderStyleSheet);
+ if (hasStyleSheet) {
+ document.head.removeChild(this._placeholderStyleSheet);
+ }
+
+ delete this._elem;
+ delete this._placeholderStyleSheet;
+ },
+
+ _showDom () {
+ this._updateMaxLength();
+ this._updateInputType();
+ this._updateStyleSheet();
+
+ this._elem.style.display = '';
+ this._delegate._hideLabels();
+
+ if (cc.sys.isMobile) {
+ this._showDomOnMobile();
+ }
+ },
+
+ _hideDom () {
+ let elem = this._elem;
+
+ elem.style.display = 'none';
+ this._delegate._showLabels();
+
+ if (cc.sys.isMobile) {
+ this._hideDomOnMobile();
+ }
+ },
+
+ _showDomOnMobile () {
+ if (cc.sys.os !== cc.sys.OS_ANDROID) {
+ return;
+ }
+
+ if (_fullscreen) {
+ cc.view.enableAutoFullScreen(false);
+ cc.screen.exitFullScreen();
+ }
+ if (_autoResize) {
+ cc.view.resizeWithBrowserSize(false);
+ }
+
+ this._adjustWindowScroll();
+ },
+
+ _hideDomOnMobile () {
+ if (cc.sys.os === cc.sys.OS_ANDROID) {
+ if (_autoResize) {
+ cc.view.resizeWithBrowserSize(true);
+ }
+ // In case enter full screen when soft keyboard still showing
+ setTimeout(function () {
+ if (!_currentEditBoxImpl) {
+ if (_fullscreen) {
+ cc.view.enableAutoFullScreen(true);
+ }
+ }
+ }, DELAY_TIME);
+ }
+
+ // Some browser like wechat on iOS need to mannully scroll back window
+ this._scrollBackWindow();
+ },
+
+ // adjust view to editBox
+ _adjustWindowScroll () {
+ let self = this;
+ setTimeout(function() {
+ if (window.scrollY < SCROLLY) {
+ self._elem.scrollIntoView({block: "start", inline: "nearest", behavior: "smooth"});
+ }
+ }, DELAY_TIME);
+ },
+
+ _scrollBackWindow () {
+ setTimeout(function () {
+ // FIX: wechat browser bug on iOS
+ // If gameContainer is included in iframe,
+ // Need to scroll the top window, not the one in the iframe
+ // Reference: https://developer.mozilla.org/en-US/docs/Web/API/Window/top
+ let sys = cc.sys;
+ if (sys.browserType === sys.BROWSER_TYPE_WECHAT && sys.os === sys.OS_IOS) {
+ window.top && window.top.scrollTo(0, 0);
+ return;
+ }
+
+ window.scrollTo(0, 0);
+ }, DELAY_TIME);
+ },
+
+ _updateCameraMatrix () {
+ let node = this._delegate.node;
+ node.getWorldMatrix(this._worldMat);
+ let worldMat = this._worldMat;
+ let nodeContentSize = node._contentSize,
+ nodeAnchorPoint = node._anchorPoint;
+
+ _vec3.x = -nodeAnchorPoint.x * nodeContentSize.width;
+ _vec3.y = -nodeAnchorPoint.y * nodeContentSize.height;
+
+ Mat4.transform(worldMat, worldMat, _vec3);
+
+ // can't find node camera in editor
+ if (CC_EDITOR) {
+ this._cameraMat = worldMat;
+ }
+ else {
+ let camera = cc.Camera.findCamera(node);
+ if (!camera) {
+ return false;
+ }
+ camera.getWorldToScreenMatrix2D(this._cameraMat);
+ Mat4.mul(this._cameraMat, this._cameraMat, worldMat);
+ }
+ return true;
+ },
+
+ _updateMatrix () {
+ if (CC_EDITOR || !this._updateCameraMatrix()) {
+ return;
+ }
+ let cameraMatm = this._cameraMat.m;
+ let node = this._delegate.node;
+ let localView = cc.view;
+ // check whether need to update
+ if (this._m00 === cameraMatm[0] && this._m01 === cameraMatm[1] &&
+ this._m04 === cameraMatm[4] && this._m05 === cameraMatm[5] &&
+ this._m12 === cameraMatm[12] && this._m13 === cameraMatm[13] &&
+ this._w === node._contentSize.width && this._h === node._contentSize.height &&
+ this._cacheViewportRect.equals(localView._viewportRect)) {
+ return;
+ }
+
+ // update matrix cache
+ this._m00 = cameraMatm[0];
+ this._m01 = cameraMatm[1];
+ this._m04 = cameraMatm[4];
+ this._m05 = cameraMatm[5];
+ this._m12 = cameraMatm[12];
+ this._m13 = cameraMatm[13];
+ this._w = node._contentSize.width;
+ this._h = node._contentSize.height;
+ // update viewport cache
+ this._cacheViewportRect.set(localView._viewportRect);
+
+ let scaleX = localView._scaleX, scaleY = localView._scaleY,
+ viewport = localView._viewportRect,
+ dpr = localView._devicePixelRatio;
+
+ scaleX /= dpr;
+ scaleY /= dpr;
+
+ let container = cc.game.container;
+ let a = cameraMatm[0] * scaleX, b = cameraMatm[1], c = cameraMatm[4], d = cameraMatm[5] * scaleY;
+
+ let offsetX = container && container.style.paddingLeft && parseInt(container.style.paddingLeft);
+ offsetX += viewport.x / dpr;
+ let offsetY = container && container.style.paddingBottom && parseInt(container.style.paddingBottom);
+ offsetY += viewport.y / dpr;
+ let tx = cameraMatm[12] * scaleX + offsetX, ty = cameraMatm[13] * scaleY + offsetY;
+
+ if (polyfill.zoomInvalid) {
+ this.setSize(node.width * a, node.height * d);
+ a = 1;
+ d = 1;
+ }
+
+ let elem = this._elem;
+ let matrix = "matrix(" + a + "," + -b + "," + -c + "," + d + "," + tx + "," + -ty + ")";
+ elem.style['transform'] = matrix;
+ elem.style['-webkit-transform'] = matrix;
+ elem.style['transform-origin'] = '0px 100% 0px';
+ elem.style['-webkit-transform-origin'] = '0px 100% 0px';
+ },
+
+ // ===========================================
+ // input type and max length
+ _updateInputType () {
+ let delegate = this._delegate,
+ inputMode = delegate.inputMode,
+ inputFlag = delegate.inputFlag,
+ returnType = delegate.returnType,
+ elem = this._elem;
+
+ // whether need to update
+ if (this._inputMode === inputMode &&
+ this._inputFlag === inputFlag &&
+ this._returnType === returnType) {
+ return;
+ }
+
+ // update cache
+ this._inputMode = inputMode;
+ this._inputFlag = inputFlag;
+ this._returnType = returnType;
+
+ // FIX ME: TextArea actually dose not support password type.
+ if (this._isTextArea) {
+ // input flag
+ let textTransform = 'none';
+ if (inputFlag === InputFlag.INITIAL_CAPS_ALL_CHARACTERS) {
+ textTransform = 'uppercase';
+ }
+ else if (inputFlag === InputFlag.INITIAL_CAPS_WORD) {
+ textTransform = 'capitalize';
+ }
+ elem.style.textTransform = textTransform;
+ return;
+ }
+
+ // begin to updateInputType
+ if (inputFlag === InputFlag.PASSWORD) {
+ elem.type = 'password';
+ return;
+ }
+
+ // input mode
+ let type = elem.type;
+ if (inputMode === InputMode.EMAIL_ADDR) {
+ type = 'email';
+ } else if(inputMode === InputMode.NUMERIC || inputMode === InputMode.DECIMAL) {
+ type = 'number';
+ } else if(inputMode === InputMode.PHONE_NUMBER) {
+ type = 'number';
+ elem.pattern = '[0-9]*';
+ } else if(inputMode === InputMode.URL) {
+ type = 'url';
+ } else {
+ type = 'text';
+
+ if (returnType === KeyboardReturnType.SEARCH) {
+ type = 'search';
+ }
+ }
+ elem.type = type;
+
+ // input flag
+ let textTransform = 'none';
+ if (inputFlag === InputFlag.INITIAL_CAPS_ALL_CHARACTERS) {
+ textTransform = 'uppercase';
+ }
+ else if (inputFlag === InputFlag.INITIAL_CAPS_WORD) {
+ textTransform = 'capitalize';
+ }
+ elem.style.textTransform = textTransform;
+ },
+
+ _updateMaxLength () {
+ let maxLength = this._delegate.maxLength;
+ if(maxLength < 0) {
+ //we can't set Number.MAX_VALUE to input's maxLength property
+ //so we use a magic number here, it should works at most use cases.
+ maxLength = 65535;
+ }
+ this._elem.maxLength = maxLength;
+ },
+
+ // ===========================================
+ // style sheet
+ _initStyleSheet () {
+ let elem = this._elem;
+ elem.style.display = 'none';
+ elem.style.border = 0;
+ elem.style.background = 'transparent';
+ elem.style.width = '100%';
+ elem.style.height = '100%';
+ elem.style.active = 0;
+ elem.style.outline = 'medium';
+ elem.style.padding = '0';
+ elem.style.textTransform = 'uppercase';
+ elem.style.position = "absolute";
+ elem.style.bottom = "0px";
+ elem.style.left = LEFT_PADDING + "px";
+ elem.className = "cocosEditBox";
+ elem.id = this._domId;
+
+ if (!this._isTextArea) {
+ elem.type = 'text';
+ elem.style['-moz-appearance'] = 'textfield';
+ }
+ else {
+ elem.style.resize = 'none';
+ elem.style.overflow_y = 'scroll';
+ }
+
+ this._placeholderStyleSheet = document.createElement('style');
+ },
+
+ _updateStyleSheet () {
+ let delegate = this._delegate,
+ elem = this._elem;
+
+ elem.value = delegate.string;
+ elem.placeholder = delegate.placeholder;
+
+ this._updateTextLabel(delegate.textLabel);
+ this._updatePlaceholderLabel(delegate.placeholderLabel);
+ },
+
+ _updateTextLabel (textLabel) {
+ if (!textLabel) {
+ return;
+ }
+ // get font
+ let font = textLabel.font;
+ if (font && !(font instanceof cc.BitmapFont)) {
+ font = font._fontFamily;
+ }
+ else {
+ font = textLabel.fontFamily;
+ }
+
+ // get font size
+ let fontSize = textLabel.fontSize * textLabel.node.scaleY;
+
+ // whether need to update
+ if (this._textLabelFont === font
+ && this._textLabelFontSize === fontSize
+ && this._textLabelFontColor === textLabel.fontColor
+ && this._textLabelAlign === textLabel.horizontalAlign) {
+ return;
+ }
+
+ // update cache
+ this._textLabelFont = font;
+ this._textLabelFontSize = fontSize;
+ this._textLabelFontColor = textLabel.fontColor;
+ this._textLabelAlign = textLabel.horizontalAlign;
+
+ let elem = this._elem;
+ // font size
+ elem.style.fontSize = `${fontSize}px`;
+ // font color
+ elem.style.color = textLabel.node.color.toCSS();
+ // font family
+ elem.style.fontFamily = font;
+ // text-align
+ switch(textLabel.horizontalAlign) {
+ case Label.HorizontalAlign.LEFT:
+ elem.style.textAlign = 'left';
+ break;
+ case Label.HorizontalAlign.CENTER:
+ elem.style.textAlign = 'center';
+ break;
+ case Label.HorizontalAlign.RIGHT:
+ elem.style.textAlign = 'right';
+ break;
+ }
+ // lineHeight
+ // Can't sync lineHeight property, because lineHeight would change the touch area of input
+ },
+
+ _updatePlaceholderLabel (placeholderLabel) {
+ if (!placeholderLabel) {
+ return;
+ }
+
+ // get font
+ let font = placeholderLabel.font;
+ if (font && !(font instanceof cc.BitmapFont)) {
+ font = placeholderLabel.font._fontFamily;
+ }
+ else {
+ font = placeholderLabel.fontFamily;
+ }
+
+ // get font size
+ let fontSize = placeholderLabel.fontSize * placeholderLabel.node.scaleY;
+
+ // whether need to update
+ if (this._placeholderLabelFont === font
+ && this._placeholderLabelFontSize === fontSize
+ && this._placeholderLabelFontColor === placeholderLabel.fontColor
+ && this._placeholderLabelAlign === placeholderLabel.horizontalAlign
+ && this._placeholderLineHeight === placeholderLabel.fontSize) {
+ return;
+ }
+
+ // update cache
+ this._placeholderLabelFont = font;
+ this._placeholderLabelFontSize = fontSize;
+ this._placeholderLabelFontColor = placeholderLabel.fontColor;
+ this._placeholderLabelAlign = placeholderLabel.horizontalAlign;
+ this._placeholderLineHeight = placeholderLabel.fontSize;
+
+ let styleEl = this._placeholderStyleSheet;
+
+ // font color
+ let fontColor = placeholderLabel.node.color.toCSS();
+ // line height
+ let lineHeight = placeholderLabel.fontSize; // top vertical align by default
+ // horizontal align
+ let horizontalAlign;
+ switch (placeholderLabel.horizontalAlign) {
+ case Label.HorizontalAlign.LEFT:
+ horizontalAlign = 'left';
+ break;
+ case Label.HorizontalAlign.CENTER:
+ horizontalAlign = 'center';
+ break;
+ case Label.HorizontalAlign.RIGHT:
+ horizontalAlign = 'right';
+ break;
+ }
+
+ styleEl.innerHTML = `#${this._domId}::-webkit-input-placeholder,#${this._domId}::-moz-placeholder,#${this._domId}:-ms-input-placeholder` +
+ `{text-transform: initial; font-family: ${font}; font-size: ${fontSize}px; color: ${fontColor}; line-height: ${lineHeight}px; text-align: ${horizontalAlign};}`;
+ // EDGE_BUG_FIX: hide clear button, because clearing input box in Edge does not emit input event
+ // issue refference: https://github.com/angular/angular/issues/26307
+ if (cc.sys.browserType === cc.sys.BROWSER_TYPE_EDGE) {
+ styleEl.innerHTML += `#${this._domId}::-ms-clear{display: none;}`;
+ }
+ },
+
+ // ===========================================
+ // handle event listeners
+ _registerEventListeners () {
+ let impl = this,
+ elem = this._elem,
+ inputLock = false,
+ cbs = this._eventListeners;
+
+ cbs.compositionStart = function () {
+ inputLock = true;
+ };
+
+ cbs.compositionEnd = function () {
+ inputLock = false;
+ impl._delegate.editBoxTextChanged(elem.value);
+ };
+
+ cbs.onInput = function () {
+ if (inputLock) {
+ return;
+ }
+ // input of number type doesn't support maxLength attribute
+ let maxLength = impl._delegate.maxLength;
+ if (maxLength >= 0) {
+ elem.value = elem.value.slice(0, maxLength);
+ }
+ impl._delegate.editBoxTextChanged(elem.value);
+ };
+
+ // There are 2 ways to focus on the input element:
+ // Click the input element, or call input.focus().
+ // Both need to adjust window scroll.
+ cbs.onClick = function (e) {
+ // In case operation sequence: click input, hide keyboard, then click again.
+ if (impl._editing) {
+ if (cc.sys.isMobile) {
+ impl._adjustWindowScroll();
+ }
+ }
+ };
+
+ cbs.onKeydown = function (e) {
+ if (e.keyCode === macro.KEY.enter) {
+ e.stopPropagation();
+ impl._delegate.editBoxEditingReturn();
+
+ if (!impl._isTextArea) {
+ elem.blur();
+ }
+ }
+ else if (e.keyCode === macro.KEY.tab) {
+ e.stopPropagation();
+ e.preventDefault();
+
+ tabIndexUtil.next(impl);
+ }
+ };
+
+ cbs.onBlur = function () {
+ // on mobile, sometimes input element doesn't fire compositionend event
+ if (cc.sys.isMobile && inputLock) {
+ cbs.compositionEnd();
+ }
+ impl._editing = false;
+ _currentEditBoxImpl = null;
+ impl._hideDom();
+ impl._delegate.editBoxEditingDidEnded();
+ };
+
+ elem.addEventListener('compositionstart', cbs.compositionStart);
+ elem.addEventListener('compositionend', cbs.compositionEnd);
+ elem.addEventListener('input', cbs.onInput);
+ elem.addEventListener('keydown', cbs.onKeydown);
+ elem.addEventListener('blur', cbs.onBlur);
+ elem.addEventListener('touchstart', cbs.onClick);
+ },
+
+ _removeEventListeners () {
+ let elem = this._elem,
+ cbs = this._eventListeners;
+
+ elem.removeEventListener('compositionstart', cbs.compositionStart);
+ elem.removeEventListener('compositionend', cbs.compositionEnd);
+ elem.removeEventListener('input', cbs.onInput);
+ elem.removeEventListener('keydown', cbs.onKeydown);
+ elem.removeEventListener('blur', cbs.onBlur);
+ elem.removeEventListener('touchstart', cbs.onClick);
+
+ cbs.compositionStart = null;
+ cbs.compositionEnd = null;
+ cbs.onInput = null;
+ cbs.onKeydown = null;
+ cbs.onBlur = null;
+ cbs.onClick = null;
+ },
+});
+
diff --git a/cocos2d/core/components/editbox/tabIndexUtil.js b/cocos2d/core/components/editbox/tabIndexUtil.js
new file mode 100644
index 00000000000..17b2ef9899c
--- /dev/null
+++ b/cocos2d/core/components/editbox/tabIndexUtil.js
@@ -0,0 +1,39 @@
+const tabIndexUtil = {
+ _tabIndexList: [],
+
+ add (editBoxImpl) {
+ let list = this._tabIndexList;
+ let index = list.indexOf(editBoxImpl);
+ if (index === -1){
+ list.push(editBoxImpl);
+ }
+ },
+
+ remove (editBoxImpl) {
+ let list = this._tabIndexList;
+ let index = list.indexOf(editBoxImpl);
+ if (index !== -1) {
+ list.splice(index, 1);
+ }
+ },
+
+ resort () {
+ this._tabIndexList.sort(function(a, b) {
+ return a._delegate._tabIndex - b._delegate._tabIndex;
+ });
+ },
+
+ next (editBoxImpl) {
+ let list = this._tabIndexList;
+ let index = list.indexOf(editBoxImpl);
+ editBoxImpl.setFocus(false);
+ if (index !== -1) {
+ let nextImpl = list[index+1];
+ if (nextImpl && nextImpl._delegate._tabIndex >= 0) {
+ nextImpl.setFocus(true);
+ }
+ }
+ },
+}
+
+module.exports = tabIndexUtil;
\ No newline at end of file
diff --git a/cocos2d/core/components/editbox/types.js b/cocos2d/core/components/editbox/types.js
index ca1757d2e46..00714373ce0 100644
--- a/cocos2d/core/components/editbox/types.js
+++ b/cocos2d/core/components/editbox/types.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/components/index.js b/cocos2d/core/components/index.js
index 30096bf46b2..65bd4bade7b 100644
--- a/cocos2d/core/components/index.js
+++ b/cocos2d/core/components/index.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -28,6 +28,16 @@ require('./CCComponent');
require('./CCComponentEventHandler');
require('./missing-script');
+// In case subContextView modules are excluded
+let SubContextView = require('./SubContextView');
+if (!SubContextView) {
+ SubContextView = cc.Class({
+ name: 'cc.SubContextView',
+ extends: cc.Component,
+ });
+ cc.SubContextView = cc.WXSubContextView = cc.SwanSubContextView = SubContextView;
+}
+
var components = [
require('./CCSprite'),
require('./CCWidget'),
@@ -46,13 +56,15 @@ var components = [
require('./CCLayout'),
require('./editbox/CCEditBox'),
require('./CCLabelOutline'),
+ require('./CCLabelShadow'),
require('./CCRichText'),
require('./CCToggleContainer'),
require('./CCToggleGroup'),
require('./CCToggle'),
require('./CCBlockInputEvents'),
require('./CCMotionStreak'),
- require('./WXSubContextView'),
+ require('./CCSafeArea'),
+ SubContextView,
];
module.exports = components;
\ No newline at end of file
diff --git a/cocos2d/core/components/missing-script.js b/cocos2d/core/components/missing-script.js
index d0e43324ade..f0e157972d3 100644
--- a/cocos2d/core/components/missing-script.js
+++ b/cocos2d/core/components/missing-script.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -25,25 +25,10 @@
****************************************************************************/
var js = cc.js;
-var BUILTIN_CLASSID_RE = require('../utils/misc').BUILTIN_CLASSID_RE;
/*
* A temp fallback to contain the original serialized data which can not be loaded.
- */
-var MissingClass = cc.Class({
- name: 'cc.MissingClass',
- properties: {
- // the serialized data for original object
- _$erialized: {
- default: null,
- visible: false,
- editorOnly: true
- }
- },
-});
-
-/*
- * A temp fallback to contain the original component which can not be loaded.
+ * Deserialized as a component by default.
*/
var MissingScript = cc.Class({
name: 'cc.MissingScript',
@@ -99,26 +84,14 @@ var MissingScript = cc.Class({
* @param {string} id
* @return {function} constructor
*/
- safeFindClass: function (id, data) {
+ safeFindClass: function (id) {
var cls = js._getClassById(id);
if (cls) {
return cls;
}
- if (id) {
- cc.deserialize.reportMissingClass(id);
- return MissingScript.getMissingWrapper(id, data);
- }
- return null;
+ cc.deserialize.reportMissingClass(id);
+ return MissingScript;
},
- getMissingWrapper: function (id, data) {
- if (data.node && (/^[0-9a-zA-Z+/]{23}$/.test(id) || BUILTIN_CLASSID_RE.test(id))) {
- // is component
- return MissingScript;
- }
- else {
- return MissingClass;
- }
- }
},
onLoad: function () {
cc.warnID(4600, this.node.name);
diff --git a/cocos2d/core/event-manager/CCEvent.js b/cocos2d/core/event-manager/CCEvent.js
index feb282dafa7..639a9450ef3 100644
--- a/cocos2d/core/event-manager/CCEvent.js
+++ b/cocos2d/core/event-manager/CCEvent.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -417,7 +417,7 @@ proto.getPreviousLocation = function () {
/**
* !#en Returns the start touch location.
- * !#zh 获获取触点落下时的位置对象,对象包含 x 和 y 属性。
+ * !#zh 获取触点落下时的位置对象,对象包含 x 和 y 属性。
* @method getStartLocation
* @returns {Vec2}
*/
diff --git a/cocos2d/core/event-manager/CCEventListener.js b/cocos2d/core/event-manager/CCEventListener.js
index cd1ba37b1c8..778c4c5fe56 100644
--- a/cocos2d/core/event-manager/CCEventListener.js
+++ b/cocos2d/core/event-manager/CCEventListener.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/event-manager/CCEventManager.js b/cocos2d/core/event-manager/CCEventManager.js
index f7ee2fc2f79..c8dcced0895 100644
--- a/cocos2d/core/event-manager/CCEventManager.js
+++ b/cocos2d/core/event-manager/CCEventManager.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -89,14 +89,14 @@ var __getListenerID = function (event) {
/**
* !#en
- * This class has been deprecated, please use cc.systemEvent or cc.EventTarget instead. See [Listen to and launch events](../../../manual/en/scripting/events.md) for details.
+ * This class has been deprecated, please use cc.systemEvent or cc.EventTarget instead. See [Listen to and launch events](../../../manual/en/scripting/events.html) for details.
*
* cc.eventManager is a singleton object which manages event listener subscriptions and event dispatching.
* The EventListener list is managed in such way so that event listeners can be added and removed
* while events are being dispatched.
*
* !#zh
- * 该类已废弃,请使用 cc.systemEvent 或 cc.EventTarget 代替,详见 [监听和发射事件](../../../manual/zh/scripting/events.md)。
+ * 该类已废弃,请使用 cc.systemEvent 或 cc.EventTarget 代替,详见 [监听和发射事件](../../../manual/zh/scripting/events.html)。
*
* 事件管理器,它主要管理事件监听器注册和派发系统事件。
*
@@ -111,30 +111,35 @@ var eventManager = {
DIRTY_FIXED_PRIORITY: 1 << 0,
DIRTY_SCENE_GRAPH_PRIORITY: 1 << 1,
DIRTY_ALL: 3,
-
+
_listenersMap: {},
_priorityDirtyFlagMap: {},
_nodeListenersMap: {},
- _nodePriorityMap: js.createMap(true),
- _globalZOrderNodeMap: [],
_toAddedListeners: [],
_toRemovedListeners: [],
- _dirtyNodes: [],
+ _dirtyListeners: {},
_inDispatch: 0,
_isEnabled: false,
- _nodePriorityIndex: 0,
+ _currentTouch: null,
+ _currentTouchListener: null,
_internalCustomListenerIDs:[],
_setDirtyForNode: function (node) {
// Mark the node dirty only when there is an event listener associated with it.
- if (this._nodeListenersMap[node._id] !== undefined) {
- this._dirtyNodes.push(node);
+ let selListeners = this._nodeListenersMap[node._id];
+ if (selListeners !== undefined) {
+ for (let j = 0, len = selListeners.length; j < len; j++) {
+ let selListener = selListeners[j];
+ let listenerID = selListener._getListenerID();
+ if (this._dirtyListeners[listenerID] == null)
+ this._dirtyListeners[listenerID] = true;
+ }
}
- if (node.getChildren) {
- var _children = node.getChildren();
- for(var i = 0, len = _children ? _children.length : 0; i < len; i++)
- this._setDirtyForNode(_children[i]);
+ if (node.childrenCount > 0) {
+ let children = node._children;
+ for(let i = 0, len = children.length; i < len; i++)
+ this._setDirtyForNode(children[i]);
}
},
@@ -156,7 +161,7 @@ var eventManager = {
listeners[i]._setPaused(true);
}
if (recursive === true) {
- var locChildren = node.getChildren();
+ var locChildren = node._children;
for (i = 0, len = locChildren ? locChildren.length : 0; i < len; i++)
this.pauseTarget(locChildren[i], true);
}
@@ -180,8 +185,8 @@ var eventManager = {
listeners[i]._setPaused(false);
}
this._setDirtyForNode(node);
- if (recursive === true && node.getChildren) {
- var locChildren = node.getChildren();
+ if (recursive === true) {
+ var locChildren = node._children;
for (i = 0, len = locChildren ? locChildren.length : 0; i < len; i++)
this.resumeTarget(locChildren[i], true);
}
@@ -222,28 +227,19 @@ var eventManager = {
},
_updateDirtyFlagForSceneGraph: function () {
- if (this._dirtyNodes.length === 0)
- return;
-
- var locDirtyNodes = this._dirtyNodes, selListeners, selListener, locNodeListenersMap = this._nodeListenersMap;
- for (var i = 0, len = locDirtyNodes.length; i < len; i++) {
- selListeners = locNodeListenersMap[locDirtyNodes[i]._id];
- if (selListeners) {
- for (var j = 0, listenersLen = selListeners.length; j < listenersLen; j++) {
- selListener = selListeners[j];
- if (selListener)
- this._setDirty(selListener._getListenerID(), this.DIRTY_SCENE_GRAPH_PRIORITY);
- }
- }
+ let locDirtyListeners = this._dirtyListeners
+ for (var selKey in locDirtyListeners) {
+ this._setDirty(selKey, this.DIRTY_SCENE_GRAPH_PRIORITY);
}
- this._dirtyNodes.length = 0;
+
+ this._dirtyListeners = {};
},
_removeAllListenersInVector: function (listenerVector) {
if (!listenerVector)
return;
var selListener;
- for (var i = 0; i < listenerVector.length;) {
+ for (var i = listenerVector.length - 1; i >= 0; i--) {
selListener = listenerVector[i];
selListener._setRegistered(false);
if (selListener._getSceneGraphPriority() != null) {
@@ -252,9 +248,7 @@ var eventManager = {
}
if (this._inDispatch === 0)
- cc.js.array.remove(listenerVector, selListener);
- else
- ++i;
+ cc.js.array.removeAt(listenerVector, i);
}
},
@@ -278,12 +272,10 @@ var eventManager = {
}
var locToAddedListeners = this._toAddedListeners, listener;
- for (i = 0; i < locToAddedListeners.length;) {
+ for (i = locToAddedListeners.length - 1; i >= 0; i--) {
listener = locToAddedListeners[i];
if (listener && listener._getListenerID() === listenerID)
- cc.js.array.remove(locToAddedListeners, listener);
- else
- ++i;
+ cc.js.array.removeAt(locToAddedListeners, i);
}
},
@@ -291,7 +283,7 @@ var eventManager = {
var dirtyFlag = this.DIRTY_NONE, locFlagMap = this._priorityDirtyFlagMap;
if (locFlagMap[listenerID])
dirtyFlag = locFlagMap[listenerID];
-
+
if (dirtyFlag !== this.DIRTY_NONE) {
// Clear the dirty flag first, if `rootNode` is null, then set its dirty flag of scene graph priority
locFlagMap[listenerID] = this.DIRTY_NONE;
@@ -302,12 +294,12 @@ var eventManager = {
if (dirtyFlag & this.DIRTY_SCENE_GRAPH_PRIORITY){
var rootEntity = cc.director.getScene();
if(rootEntity)
- this._sortListenersOfSceneGraphPriority(listenerID, rootEntity);
+ this._sortListenersOfSceneGraphPriority(listenerID);
}
}
},
- _sortListenersOfSceneGraphPriority: function (listenerID, rootNode) {
+ _sortListenersOfSceneGraphPriority: function (listenerID) {
var listeners = this._getListeners(listenerID);
if (!listeners)
return;
@@ -316,25 +308,33 @@ var eventManager = {
if (!sceneGraphListener || sceneGraphListener.length === 0)
return;
- // Reset priority index
- this._nodePriorityIndex = 0;
- this._nodePriorityMap = js.createMap(true);
-
- this._visitTarget(rootNode, true);
-
// After sort: priority < 0, > 0
listeners.getSceneGraphPriorityListeners().sort(this._sortEventListenersOfSceneGraphPriorityDes);
},
_sortEventListenersOfSceneGraphPriorityDes: function (l1, l2) {
- var locNodePriorityMap = eventManager._nodePriorityMap,
- node1 = l1._getSceneGraphPriority(),
+ let node1 = l1._getSceneGraphPriority(),
node2 = l2._getSceneGraphPriority();
- if (!l2 || !node2 || !locNodePriorityMap[node2._id])
+
+ if (!l2 || !node2 || !node2._activeInHierarchy || node2._parent === null)
return -1;
- else if (!l1 || !node1 || !locNodePriorityMap[node1._id])
+ else if (!l1 || !node1 || !node1._activeInHierarchy || node1._parent === null)
return 1;
- return locNodePriorityMap[node2._id] - locNodePriorityMap[node1._id];
+
+ let p1 = node1, p2 = node2, ex = false;
+ while (p1._parent._id !== p2._parent._id) {
+ p1 = p1._parent._parent === null ? (ex = true) && node2 : p1._parent;
+ p2 = p2._parent._parent === null ? (ex = true) && node1 : p2._parent;
+ }
+
+ if (p1._id === p2._id) {
+ if (p1._id === node2._id)
+ return -1;
+ if (p1._id === node1._id)
+ return 1;
+ }
+
+ return ex ? p1._localZOrder - p2._localZOrder : p2._localZOrder - p1._localZOrder;
},
_sortListenersOfFixedPriority: function (listenerID) {
@@ -368,31 +368,28 @@ var eventManager = {
var i, selListener, idx, toRemovedListeners = this._toRemovedListeners;
if (sceneGraphPriorityListeners) {
- for (i = 0; i < sceneGraphPriorityListeners.length;) {
+ for (i = sceneGraphPriorityListeners.length - 1; i >= 0; i--) {
selListener = sceneGraphPriorityListeners[i];
if (!selListener._isRegistered()) {
- cc.js.array.remove(sceneGraphPriorityListeners, selListener);
+ cc.js.array.removeAt(sceneGraphPriorityListeners, i);
// if item in toRemove list, remove it from the list
idx = toRemovedListeners.indexOf(selListener);
if(idx !== -1)
toRemovedListeners.splice(idx, 1);
- } else
- ++i;
+ }
}
}
if (fixedPriorityListeners) {
- for (i = 0; i < fixedPriorityListeners.length;) {
+ for (i = fixedPriorityListeners.length - 1; i >= 0; i--) {
selListener = fixedPriorityListeners[i];
if (!selListener._isRegistered()) {
- cc.js.array.remove(fixedPriorityListeners, selListener);
+ cc.js.array.removeAt(fixedPriorityListeners, i);
// if item in toRemove list, remove it from the list
idx = toRemovedListeners.indexOf(selListener);
if(idx !== -1)
toRemovedListeners.splice(idx, 1);
}
- else
- ++i;
}
}
@@ -484,7 +481,7 @@ var eventManager = {
_onTouchEventCallback: function (listener, argsObj) {
// Skip if the listener was removed.
- if (!listener._isRegistered)
+ if (!listener._isRegistered())
return false;
var event = argsObj.event, selTouch = event.currentTouch;
@@ -493,14 +490,29 @@ var eventManager = {
var isClaimed = false, removedIdx;
var getCode = event.getEventCode(), EventTouch = cc.Event.EventTouch;
if (getCode === EventTouch.BEGAN) {
+ if (!cc.macro.ENABLE_MULTI_TOUCH && eventManager._currentTouch) {
+ let node = eventManager._currentTouchListener._node;
+ if (node && node.activeInHierarchy) {
+ return false;
+ }
+ }
+
if (listener.onTouchBegan) {
isClaimed = listener.onTouchBegan(selTouch, event);
- if (isClaimed && listener._registered)
+ if (isClaimed && listener._registered) {
listener._claimedTouches.push(selTouch);
+ eventManager._currentTouchListener = listener;
+ eventManager._currentTouch = selTouch;
+ }
}
} else if (listener._claimedTouches.length > 0
&& ((removedIdx = listener._claimedTouches.indexOf(selTouch)) !== -1)) {
isClaimed = true;
+
+ if (!cc.macro.ENABLE_MULTI_TOUCH && eventManager._currentTouch && eventManager._currentTouch !== selTouch) {
+ return false;
+ }
+
if (getCode === EventTouch.MOVED && listener.onTouchMoved) {
listener.onTouchMoved(selTouch, event);
} else if (getCode === EventTouch.ENDED) {
@@ -508,11 +520,13 @@ var eventManager = {
listener.onTouchEnded(selTouch, event);
if (listener._registered)
listener._claimedTouches.splice(removedIdx, 1);
- } else if (getCode === EventTouch.CANCELLED) {
+ eventManager._clearCurTouch();
+ } else if (getCode === EventTouch.CANCELED) {
if (listener.onTouchCancelled)
listener.onTouchCancelled(selTouch, event);
if (listener._registered)
listener._claimedTouches.splice(removedIdx, 1);
+ eventManager._clearCurTouch();
}
}
@@ -522,7 +536,7 @@ var eventManager = {
return true;
}
- if (isClaimed && listener._registered && listener.swallowTouches) {
+ if (isClaimed && listener.swallowTouches) {
if (argsObj.needsMutableSet)
argsObj.touches.splice(selTouch, 1);
return true;
@@ -579,7 +593,7 @@ var eventManager = {
listener.onTouchesMoved(touches, event);
else if (getCode === EventTouch.ENDED && listener.onTouchesEnded)
listener.onTouchesEnded(touches, event);
- else if (getCode === EventTouch.CANCELLED && listener.onTouchesCancelled)
+ else if (getCode === EventTouch.CANCELED && listener.onTouchesCancelled)
listener.onTouchesCancelled(touches, event);
// If the event was stopped, return directly.
@@ -655,43 +669,6 @@ var eventManager = {
locDirtyFlagMap[listenerID] = flag | locDirtyFlagMap[listenerID];
},
- _visitTarget: function (node, isRootNode) {
- // sortAllChildren is performed the next frame, but the event is executed immediately.
- if (node._reorderChildDirty) {
- node.sortAllChildren();
- }
- var children = node.getChildren(), i = 0;
- var childrenCount = children.length, locGlobalZOrderNodeMap = this._globalZOrderNodeMap, locNodeListenersMap = this._nodeListenersMap;
-
- if (childrenCount > 0) {
- if (locNodeListenersMap[node._id] !== undefined) {
- if (!locGlobalZOrderNodeMap)
- locGlobalZOrderNodeMap = [];
- locGlobalZOrderNodeMap.push(node._id);
- }
-
- var child;
- for (; i < childrenCount; i++) {
- child = children[i];
- if (child)
- this._visitTarget(child, false);
- }
- } else {
- if (locNodeListenersMap[node._id] !== undefined) {
- if (!locGlobalZOrderNodeMap)
- locGlobalZOrderNodeMap = [];
- locGlobalZOrderNodeMap.push(node._id);
- }
- }
-
- if (isRootNode) {
- let locNodePriorityMap = this._nodePriorityMap;
- for (let j = 0; j < locGlobalZOrderNodeMap.length; j++)
- locNodePriorityMap[locGlobalZOrderNodeMap[j]] = ++this._nodePriorityIndex;
- this._globalZOrderNodeMap.length = 0;
- }
- },
-
_sortNumberAsc: function (a, b) {
return a - b;
},
@@ -825,22 +802,29 @@ var eventManager = {
if (!isFound) {
var locToAddedListeners = this._toAddedListeners;
- for (var i = 0, len = locToAddedListeners.length; i < len; i++) {
+ for (var i = locToAddedListeners.length - 1; i >= 0; i--) {
var selListener = locToAddedListeners[i];
if (selListener === listener) {
- cc.js.array.remove(locToAddedListeners, selListener);
+ cc.js.array.removeAt(locToAddedListeners, i);
selListener._setRegistered(false);
break;
}
}
}
+
+ this._currentTouchListener === listener && this._clearCurTouch();
+ },
+
+ _clearCurTouch () {
+ this._currentTouchListener = null;
+ this._currentTouch = null;
},
_removeListenerInCallback: function(listeners, callback){
if (listeners == null)
return false;
- for (var i = 0, len = listeners.length; i < len; i++) {
+ for (var i = listeners.length - 1; i >= 0; i--) {
var selListener = listeners[i];
if (selListener._onCustomEvent === callback || selListener._onEvent === callback) {
selListener._setRegistered(false);
@@ -850,7 +834,7 @@ var eventManager = {
}
if (this._inDispatch === 0)
- cc.js.array.remove(listeners, selListener);
+ cc.js.array.removeAt(listeners, i);
else
this._toRemovedListeners.push(selListener);
return true;
@@ -863,7 +847,7 @@ var eventManager = {
if (listeners == null)
return false;
- for (var i = 0, len = listeners.length; i < len; i++) {
+ for (var i = listeners.length - 1; i >= 0; i--) {
var selListener = listeners[i];
if (selListener === listener) {
selListener._setRegistered(false);
@@ -873,7 +857,7 @@ var eventManager = {
}
if (this._inDispatch === 0)
- cc.js.array.remove(listeners, selListener);
+ cc.js.array.removeAt(listeners, i);
else
this._toRemovedListeners.push(selListener);
return true;
@@ -909,8 +893,6 @@ var eventManager = {
if (listenerType._id !== undefined) {
// Ensure the node is removed from these immediately also.
// Don't want any dangling pointers or the possibility of dealing with deleted objects..
- delete _t._nodePriorityMap[listenerType._id];
- cc.js.array.remove(_t._dirtyNodes, listenerType);
var listeners = _t._nodeListenersMap[listenerType._id], i;
if (listeners) {
var listenersCopy = cc.js.array.copy(listeners);
@@ -936,7 +918,7 @@ var eventManager = {
}
if (recursive === true) {
- var locChildren = listenerType.getChildren(), len;
+ var locChildren = listenerType.children, len;
for (i = 0, len = locChildren.length; i< len; i++)
_t.removeListeners(locChildren[i], true);
}
@@ -1084,8 +1066,8 @@ var eventManager = {
js.get(cc, 'eventManager', function () {
- cc.warnID(1405, 'cc.eventManager', 'cc.EventTarget or cc.systemEvent');
+ cc.errorID(1405, 'cc.eventManager', 'cc.EventTarget or cc.systemEvent');
return eventManager;
});
-module.exports = eventManager;
+module.exports = cc.internal.eventManager = eventManager;
diff --git a/cocos2d/core/event-manager/CCTouch.js b/cocos2d/core/event-manager/CCTouch.js
index 76c01f95c09..5b915924b3a 100644
--- a/cocos2d/core/event-manager/CCTouch.js
+++ b/cocos2d/core/event-manager/CCTouch.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -81,7 +81,7 @@ cc.Touch.prototype = {
/**
* !#en Returns the start touch location in OpenGL coordinates.
- * !#zh 获获取触点落下时的位置对象,对象包含 x 和 y 属性。
+ * !#zh 获取触点落下时的位置对象,对象包含 x 和 y 属性。
* @method getStartLocation
* @returns {Vec2}
*/
diff --git a/cocos2d/core/event-manager/index.js b/cocos2d/core/event-manager/index.js
index 856a86b8389..bd26cd049d4 100644
--- a/cocos2d/core/event-manager/index.js
+++ b/cocos2d/core/event-manager/index.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/event/event-listeners.js b/cocos2d/core/event/event-listeners.js
index d238cf06dc5..04eef9a7fa4 100644
--- a/cocos2d/core/event/event-listeners.js
+++ b/cocos2d/core/event/event-listeners.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -24,29 +24,27 @@
THE SOFTWARE.
****************************************************************************/
-var js = cc.js;
-var CallbacksHandler = require('../platform/callbacks-invoker').CallbacksHandler;
+const js = cc.js;
+const CallbacksInvoker = require('../platform/callbacks-invoker');
-// Extends CallbacksHandler to handle and invoke event callbacks.
+// Extends CallbacksInvoker to handle and invoke event callbacks.
function EventListeners () {
- CallbacksHandler.call(this);
+ CallbacksInvoker.call(this);
}
-js.extend(EventListeners, CallbacksHandler);
+js.extend(EventListeners, CallbacksInvoker);
-EventListeners.prototype.invoke = function (event, captureListeners) {
- var key = event.type;
- var list = this._callbackTable[key];
+EventListeners.prototype.emit = function (event, captureListeners) {
+ let key = event.type;
+ const list = this._callbackTable[key];
if (list) {
- var rootInvoker = !list.isInvoking;
+ let rootInvoker = !list.isInvoking;
list.isInvoking = true;
- var callbacks = list.callbacks;
- var targets = list.targets;
- for (var i = 0, len = callbacks.length; i < len; ++i) {
- var callback = callbacks[i];
- if (callback) {
- var target = targets[i] || event.currentTarget;
- callback.call(target, event, captureListeners);
+ const infos = list.callbackInfos;
+ for (let i = 0, len = infos.length; i < len; ++i) {
+ const info = infos[i];
+ if (info && info.callback) {
+ info.callback.call(info.target, event, captureListeners);
if (event._propagationImmediateStopped) {
break;
}
diff --git a/cocos2d/core/event/event-target.js b/cocos2d/core/event/event-target.js
index bdf2c40e720..20948173664 100644
--- a/cocos2d/core/event/event-target.js
+++ b/cocos2d/core/event/event-target.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -54,6 +54,7 @@ var fastRemove = js.array.fastRemove;
* 但是其他对象也可以是事件目标。
*
* @class EventTarget
+ * @extends CallbacksInvoker
*/
function EventTarget () {
CallbacksInvoker.call(this);
@@ -95,17 +96,19 @@ var proto = EventTarget.prototype;
* cc.log("fire in the hole");
* }, node);
*/
-proto.on = function (type, callback, target) {
+proto.__on = proto.on;
+proto.on = function (type, callback, target, once) {
if (!callback) {
cc.errorID(6800);
return;
}
if ( !this.hasEventListener(type, callback, target) ) {
- this.add(type, callback, target);
+ this.__on(type, callback, target, once);
- if (target && target.__eventTargets)
+ if (target && target.__eventTargets) {
target.__eventTargets.push(this);
+ }
}
return callback;
};
@@ -131,12 +134,22 @@ proto.on = function (type, callback, target) {
* // remove all fire event listeners
* eventTarget.off('fire');
*/
+proto.__off = proto.off;
proto.off = function (type, callback, target) {
if (!callback) {
+ let list = this._callbackTable[type];
+ if (!list) return;
+ let infos = list.callbackInfos;
+ for (let i = 0; i < infos.length; ++i) {
+ let target = infos[i] && infos[i].target;
+ if (target && target.__eventTargets) {
+ fastRemove(target.__eventTargets, this);
+ }
+ }
this.removeAll(type);
}
else {
- this.remove(type, callback, target);
+ this.__off(type, callback, target);
if (target && target.__eventTargets) {
fastRemove(target.__eventTargets, this);
@@ -155,7 +168,13 @@ proto.off = function (type, callback, target) {
* @method targetOff
* @param {Object} target - The target to be searched for all related listeners
*/
-proto.targetOff = proto.removeAll;
+proto.targetOff = function (target) {
+ this.removeAll(target);
+
+ if (target && target.__eventTargets) {
+ fastRemove(target.__eventTargets, this);
+ }
+};
/**
* !#en
@@ -180,51 +199,42 @@ proto.targetOff = proto.removeAll;
* }, node);
*/
proto.once = function (type, callback, target) {
- var eventType_hasOnceListener = '__ONCE_FLAG:' + type;
- var hasOnceListener = this.hasEventListener(eventType_hasOnceListener, callback, target);
- if (!hasOnceListener) {
- var self = this;
- var onceWrapper = function (arg1, arg2, arg3, arg4, arg5) {
- self.off(type, onceWrapper, target);
- self.remove(eventType_hasOnceListener, callback, target);
- callback.call(this, arg1, arg2, arg3, arg4, arg5);
- };
- this.on(type, onceWrapper, target);
- this.add(eventType_hasOnceListener, callback, target);
- }
+ this.on(type, callback, target, true);
};
/**
* !#en
- * Trigger an event directly with the event name and necessary arguments.
+ * Send an event with the event object.
* !#zh
- * 通过事件名发送自定义事件
+ * 通过事件对象派发事件
*
- * @method emit
- * @param {String} type - event type
- * @param {*} [arg1] - First argument
- * @param {*} [arg2] - Second argument
- * @param {*} [arg3] - Third argument
- * @param {*} [arg4] - Fourth argument
- * @param {*} [arg5] - Fifth argument
- * @example
- *
- * eventTarget.emit('fire', event);
- * eventTarget.emit('fire', message, emitter);
+ * @method dispatchEvent
+ * @param {Event} event
*/
-proto.emit = CallbacksInvoker.prototype.invoke;
+proto.dispatchEvent = function (event) {
+ this.emit(event.type, event);
+};
/**
* !#en
- * Send an event with the event object.
+ * Destroy all callbackInfos.
* !#zh
- * 通过事件对象派发事件
+ * 销毁记录的事件
*
- * @method dispatchEvent
- * @param {Event} event
+ * @method clear
*/
-proto.dispatchEvent = function (event) {
- this.invoke(event.type, event);
+proto.clear = function () {
+ // remove all callback
+ for (const key in this._callbackTable) {
+ const list = this._callbackTable[key];
+ const infos = list.callbackInfos;
+ for (let i = infos.length - 1; i >= 0; i--) {
+ const info = infos[i];
+ if (info) {
+ this.off(key, info.callback, info.target);
+ }
+ }
+ }
};
cc.EventTarget = module.exports = EventTarget;
diff --git a/cocos2d/core/event/event.js b/cocos2d/core/event/event.js
index 21fe7e4980e..4fffc599a35 100644
--- a/cocos2d/core/event/event.js
+++ b/cocos2d/core/event/event.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/event/index.js b/cocos2d/core/event/index.js
index 25158f1a57c..ac196a3f523 100644
--- a/cocos2d/core/event/index.js
+++ b/cocos2d/core/event/index.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/event/system-event.js b/cocos2d/core/event/system-event.js
index 1ef25b27e70..f287b36e608 100644
--- a/cocos2d/core/event/system-event.js
+++ b/cocos2d/core/event/system-event.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -64,10 +64,17 @@ var EventType = cc.Enum({
});
/**
- * !#en The System event, it currently supports the key events and accelerometer events
- * !#zh 系统事件,它目前支持按键事件和重力感应事件
+ * !#en
+ * The System event, it currently supports keyboard events and accelerometer events.
+ * You can get the SystemEvent instance with cc.systemEvent.
+ * !#zh
+ * 系统事件,它目前支持按键事件和重力感应事件。
+ * 你可以通过 cc.systemEvent 获取到 SystemEvent 的实例。
* @class SystemEvent
* @extends EventTarget
+ * @example
+ * cc.systemEvent.on(cc.SystemEvent.EventType.DEVICEMOTION, this.onDeviceMotionEvent, this);
+ * cc.systemEvent.off(cc.SystemEvent.EventType.DEVICEMOTION, this.onDeviceMotionEvent, this);
*/
var keyboardListener = null;
@@ -87,7 +94,19 @@ var SystemEvent = cc.Class({
* @param {Boolean} isEnable
*/
setAccelerometerEnabled: function (isEnable) {
- inputManger.setAccelerometerEnabled(isEnable);
+ if (CC_EDITOR) {
+ return;
+ }
+
+ // for iOS 13+
+ if (isEnable && window.DeviceMotionEvent && typeof DeviceMotionEvent.requestPermission === 'function') {
+ DeviceMotionEvent.requestPermission().then(response => {
+ console.log(`Device Motion Event request permission: ${response}`);
+ inputManger.setAccelerometerEnabled(response === 'granted');
+ });
+ } else {
+ inputManger.setAccelerometerEnabled(isEnable);
+ }
},
/**
@@ -97,11 +116,17 @@ var SystemEvent = cc.Class({
* @param {Number} interval
*/
setAccelerometerInterval: function(interval) {
+ if (CC_EDITOR) {
+ return;
+ }
inputManger.setAccelerometerInterval(interval);
},
- on: function (type, callback, target) {
- this._super(type, callback, target);
+ on: function (type, callback, target, once) {
+ if (CC_EDITOR) {
+ return;
+ }
+ this._super(type, callback, target, once);
// Keyboard
if (type === EventType.KEY_DOWN || type === EventType.KEY_UP) {
@@ -142,6 +167,9 @@ var SystemEvent = cc.Class({
off: function (type, callback, target) {
+ if (CC_EDITOR) {
+ return;
+ }
this._super(type, callback, target);
// Keyboard
@@ -162,8 +190,7 @@ var SystemEvent = cc.Class({
});
cc.SystemEvent = module.exports = SystemEvent;
-if (!CC_EDITOR) {
-/**
+/**
* @module cc
*/
@@ -172,6 +199,5 @@ if (!CC_EDITOR) {
* !#zh 系统事件单例,方便全局使用
* @property systemEvent
* @type {SystemEvent}
- */
- cc.systemEvent = new cc.SystemEvent();
-}
\ No newline at end of file
+ */
+cc.systemEvent = new cc.SystemEvent();
diff --git a/cocos2d/core/geom-utils/aabb.ts b/cocos2d/core/geom-utils/aabb.ts
new file mode 100644
index 00000000000..b6b29acaa2e
--- /dev/null
+++ b/cocos2d/core/geom-utils/aabb.ts
@@ -0,0 +1,166 @@
+/****************************************************************************
+ Copyright (c) 2019 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import Vec3 from '../value-types/vec3';
+import Mat3 from '../value-types/mat3';
+import enums from './enums';
+
+let _v3_tmp = new Vec3();
+let _v3_tmp2 = new Vec3();
+let _m3_tmp = new Mat3();
+
+// https://zeuxcg.org/2010/10/17/aabb-from-obb-with-component-wise-abs/
+let transform_extent_m4 = function (out, extent, m4) {
+ let _m3_tmpm = _m3_tmp.m, m4m = m4.m;
+ _m3_tmpm[0] = Math.abs(m4m[0]); _m3_tmpm[1] = Math.abs(m4m[1]); _m3_tmpm[2] = Math.abs(m4m[2]);
+ _m3_tmpm[3] = Math.abs(m4m[4]); _m3_tmpm[4] = Math.abs(m4m[5]); _m3_tmpm[5] = Math.abs(m4m[6]);
+ _m3_tmpm[6] = Math.abs(m4m[8]); _m3_tmpm[7] = Math.abs(m4m[9]); _m3_tmpm[8] = Math.abs(m4m[10]);
+ Vec3.transformMat3(out, extent, _m3_tmp);
+};
+
+/**
+ * Aabb
+ * @class geomUtils.Aabb
+ */
+export default class aabb {
+
+ /**
+ * create a new aabb
+ * @method create
+ * @param {number} px X coordinates for aabb's original point
+ * @param {number} py Y coordinates for aabb's original point
+ * @param {number} pz Z coordinates for aabb's original point
+ * @param {number} w the half of aabb width
+ * @param {number} h the half of aabb height
+ * @param {number} l the half of aabb length
+ * @return {geomUtils.Aabb}
+ */
+ public static create (px, py, pz, w, h, l) {
+ return new aabb(px, py, pz, w, h, l);
+ }
+
+ /**
+ * clone a new aabb
+ * @method clone
+ * @param {geomUtils.Aabb} a the source aabb
+ * @return {geomUtils.Aabb}
+ */
+ public static clone (a) {
+ return new aabb(a.center.x, a.center.y, a.center.z,
+ a.halfExtents.x, a.halfExtents.y, a.halfExtents.z);
+ }
+
+ /**
+ * copy the values from one aabb to another
+ * @method copy
+ * @param {geomUtils.Aabb} out the receiving aabb
+ * @param {geomUtils.Aabb} a the source aabb
+ * @return {geomUtils.Aabb}
+ */
+ public static copy (out, a) {
+ Vec3.copy(out.center, a.center);
+ Vec3.copy(out.halfExtents, a.halfExtents);
+
+ return out;
+ }
+
+ /**
+ * create a new aabb from two corner points
+ * @method fromPoints
+ * @param {geomUtils.Aabb} out the receiving aabb
+ * @param {Vec3} minPos lower corner position of the aabb
+ * @param {Vec3} maxPos upper corner position of the aabb
+ * @return {geomUtils.Aabb}
+ */
+ public static fromPoints (out, minPos, maxPos) {
+ Vec3.scale(out.center, Vec3.add(_v3_tmp, minPos, maxPos), 0.5);
+ Vec3.scale(out.halfExtents, Vec3.sub(_v3_tmp2, maxPos, minPos), 0.5);
+ return out;
+ }
+
+ /**
+ * Set the components of a aabb to the given values
+ * @method set
+ * @param {geomUtils.Aabb} out the receiving aabb
+ * @param {number} px X coordinates for aabb's original point
+ * @param {number} py Y coordinates for aabb's original point
+ * @param {number} pz Z coordinates for aabb's original point
+ * @param {number} w the half of aabb width
+ * @param {number} h the half of aabb height
+ * @param {number} l the half of aabb length
+ * @return {geomUtils.Aabb} out
+ */
+ public static set (out, px, py, pz, w, h, l) {
+ Vec3.set(out.center, px, py, pz);
+ Vec3.set(out.halfExtents, w, h, l);
+ return out;
+ }
+
+ /**
+ * @property {Vec3} center
+ */
+ center: Vec3;
+ /**
+ * @property {Vec3} halfExtents
+ */
+ halfExtents: Vec3;
+ /**
+ * @property {number} _type
+ */
+ _type: number;
+
+ constructor (px: number, py: number, pz: number, w: number, h: number, l: number) {
+ this._type = enums.SHAPE_AABB;
+ this.center = new Vec3(px, py, pz);
+ this.halfExtents = new Vec3(w, h, l);
+ }
+
+
+ /**
+ * Get the bounding points of this shape
+ * @method getBoundary
+ * @param {Vec3} minPos
+ * @param {Vec3} maxPos
+ */
+ getBoundary (minPos, maxPos) {
+ Vec3.sub(minPos, this.center, this.halfExtents);
+ Vec3.add(maxPos, this.center, this.halfExtents);
+ }
+
+ /**
+ * Transform this shape
+ * @method transform
+ * @param {Mat4} m the transform matrix
+ * @param {Vec3} pos the position part of the transform
+ * @param {Quat} rot the rotation part of the transform
+ * @param {Vec3} scale the scale part of the transform
+ * @param {geomUtils.Aabb} [out] the target shape
+ */
+ transform (m, pos, rot, scale, out) {
+ if (!out) out = this;
+ Vec3.transformMat4(out.center, this.center, m);
+ transform_extent_m4(out.halfExtents, this.halfExtents, m);
+ }
+}
diff --git a/cocos2d/core/geom-utils/distance.ts b/cocos2d/core/geom-utils/distance.ts
new file mode 100644
index 00000000000..94365ce2224
--- /dev/null
+++ b/cocos2d/core/geom-utils/distance.ts
@@ -0,0 +1,150 @@
+/****************************************************************************
+ Copyright (c) 2019 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import { Vec3 } from '../value-types';
+import aabb from './aabb';
+import obb from './obb';
+import plane from './plane';
+const X = new Vec3();
+const Y = new Vec3();
+const Z = new Vec3();
+const d = new Vec3();
+const min = new Vec3();
+const max = new Vec3();
+const u = new Array(3);
+const e = new Array(3);
+
+/**
+ * Some helpful utilities
+ * @module cc.geomUtils
+ */
+
+/**
+ * !#en
+ * the distance between a point and a plane
+ * !#zh
+ * 计算点和平面之间的距离。
+ * @method point_plane
+ * @param {Vec3} point
+ * @param {Plane} plane
+ * @return {Number} Distance
+ */
+export function point_plane (point: Vec3, plane_: plane) {
+ return Vec3.dot(plane_.n, point) - plane_.d;
+}
+
+/**
+ * !#en
+ * the closest point on plane to a given point
+ * !#zh
+ * 计算平面上最接近给定点的点。
+ * @method pt_point_plane
+ * @param {Vec3} out Closest point
+ * @param {Vec3} point Given point
+ * @param {Plane} plane
+ * @return {Vec3} Closest point
+ */
+export function pt_point_plane (out: Vec3, point: Vec3, plane_: plane) {
+ const t = point_plane(point, plane_);
+ return Vec3.subtract(out, point, Vec3.multiplyScalar(out, plane_.n, t));
+}
+
+/**
+ * !#en
+ * the closest point on aabb to a given point
+ * !#zh
+ * 计算 aabb 上最接近给定点的点。
+ * @method pt_point_aabb
+ * @param {Vec3} out Closest point.
+ * @param {Vec3} point Given point.
+ * @param {Aabb} aabb Align the axis around the box.
+ * @return {Vec3} Closest point.
+ */
+export function pt_point_aabb (out: Vec3, point: Vec3, aabb_: aabb): Vec3 {
+ Vec3.copy(out, point);
+ Vec3.subtract(min, aabb_.center, aabb_.halfExtents);
+ Vec3.add(max, aabb_.center, aabb_.halfExtents);
+
+ out.x = (out.x < min.x) ? min.x : out.x;
+ out.y = (out.y < min.x) ? min.y : out.y;
+ out.z = (out.z < min.x) ? min.z : out.z;
+
+ out.x = (out.x > max.x) ? max.x : out.x;
+ out.y = (out.y > max.x) ? max.y : out.y;
+ out.z = (out.z > max.x) ? max.z : out.z;
+ return out;
+}
+
+/**
+ * !#en
+ * the closest point on obb to a given point
+ * !#zh
+ * 计算 obb 上最接近给定点的点。
+ * @method pt_point_obb
+ * @param {Vec3} out Closest point
+ * @param {Vec3} point Given point
+ * @param {Obb} obb Direction box
+ * @return {Vec3} closest point
+ */
+export function pt_point_obb (out: Vec3, point: Vec3, obb_: obb): Vec3 {
+ let obbm = obb_.orientation.m;
+ Vec3.set(X, obbm[0], obbm[1], obbm[2]);
+ Vec3.set(Y, obbm[3], obbm[4], obbm[5]);
+ Vec3.set(Z, obbm[6], obbm[7], obbm[8]);
+
+ u[0] = X;
+ u[1] = Y;
+ u[2] = Z;
+ e[0] = obb_.halfExtents.x;
+ e[1] = obb_.halfExtents.y;
+ e[2] = obb_.halfExtents.z;
+
+ Vec3.subtract(d, point, obb_.center);
+
+ // Start result at center of obb; make steps from there
+ Vec3.set(out, obb_.center.x, obb_.center.y, obb_.center.z);
+
+ // For each OBB axis...
+ for (let i = 0; i < 3; i++) {
+
+ // ...project d onto that axis to get the distance
+ // along the axis of d from the obb center
+ let dist = Vec3.dot(d, u[i]);
+
+ // if distance farther than the obb extents, clamp to the obb
+ if (dist > e[i]) {
+ dist = e[i];
+ }
+ if (dist < -e[i]) {
+ dist = -e[i];
+ }
+
+ // Step that distance along the axis to get world coordinate
+ out.x += dist * u[i].x;
+ out.y += dist * u[i].y;
+ out.z += dist * u[i].z;
+ }
+ return out;
+}
diff --git a/cocos2d/core/geom-utils/enums.ts b/cocos2d/core/geom-utils/enums.ts
new file mode 100644
index 00000000000..6b87826b335
--- /dev/null
+++ b/cocos2d/core/geom-utils/enums.ts
@@ -0,0 +1,89 @@
+/****************************************************************************
+ Copyright (c) 2019 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+/**
+ * !#en Shape type.
+ * @enum geomUtils.enums
+ */
+export default {
+ /**
+ * !#en Ray.
+ * !#zh 射线。
+ * @property {Number} SHAPE_RAY
+ * @default 1 << 0
+ */
+ SHAPE_RAY: (1 << 0),
+ /**
+ * !#en Line.
+ * !#zh 直线。
+ * @property {Number} SHAPE_LINE
+ * @default 2
+ */
+ SHAPE_LINE: (1 << 1),
+ /**
+ * !#en Sphere.
+ * !#zh 球。
+ * @property {Number} SHAPE_SPHERE
+ * @default 4
+ */
+ SHAPE_SPHERE: (1 << 2),
+ /**
+ * !#en Aabb.
+ * !#zh 包围盒。
+ * @property {Number} SHAPE_AABB
+ */
+ SHAPE_AABB: (1 << 3),
+ /**
+ * !#en Obb.
+ * !#zh 有向包围盒。
+ * @property {Number} SHAPE_OBB
+ */
+ SHAPE_OBB: (1 << 4),
+ /**
+ * !#en Plane.
+ * !#zh 平面。
+ * @property {Number} SHAPE_PLANE
+ */
+ SHAPE_PLANE: (1 << 5),
+ /**
+ * !#en Triangle.
+ * !#zh 三角形。
+ * @property {Number} SHAPE_TRIANGLE
+ */
+ SHAPE_TRIANGLE: (1 << 6),
+ /**
+ * !#en Frustum.
+ * !#zh 平截头体。
+ * @property {Number} SHAPE_FRUSTUM
+ */
+ SHAPE_FRUSTUM: (1 << 7),
+ /**
+ * !#en frustum accurate.
+ * !#zh 平截头体。
+ * @property {Number} SHAPE_FRUSTUM_ACCURATE
+ */
+ SHAPE_FRUSTUM_ACCURATE: (1 << 8),
+};
+
\ No newline at end of file
diff --git a/cocos2d/core/geom-utils/frustum.ts b/cocos2d/core/geom-utils/frustum.ts
new file mode 100644
index 00000000000..51610f8c396
--- /dev/null
+++ b/cocos2d/core/geom-utils/frustum.ts
@@ -0,0 +1,214 @@
+/****************************************************************************
+ Copyright (c) 2019 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import { Mat4, Vec3 } from '../value-types';
+import enums from './enums';
+import plane from './plane';
+
+const _v = new Array(8);
+_v[0] = new Vec3(1, 1, 1);
+_v[1] = new Vec3(-1, 1, 1);
+_v[2] = new Vec3(-1, -1, 1);
+_v[3] = new Vec3(1, -1, 1);
+_v[4] = new Vec3(1, 1, -1);
+_v[5] = new Vec3(-1, 1, -1);
+_v[6] = new Vec3(-1, -1, -1);
+_v[7] = new Vec3(1, -1, -1);
+
+/**
+ * !#en frustum
+ * !#zh 平截头体
+ * @class geomUtils.Frustum
+ */
+export default class frustum {
+
+ /**
+ * Set whether to use accurate intersection testing function on this frustum
+ * @property {boolean} accurate
+ */
+ set accurate (b: boolean) {
+ this._type = b ? enums.SHAPE_FRUSTUM_ACCURATE : enums.SHAPE_FRUSTUM;
+ }
+
+ public static createOrtho = (() => {
+ const _temp_v3 = new Vec3();
+ return (out: frustum, width: number, height: number, near: number, far: number, transform: Mat4) => {
+ const halfWidth = width / 2;
+ const halfHeight = height / 2;
+ Vec3.set(_temp_v3, halfWidth, halfHeight, near);
+ Vec3.transformMat4(out.vertices[0], _temp_v3, transform);
+ Vec3.set(_temp_v3, -halfWidth, halfHeight, near);
+ Vec3.transformMat4(out.vertices[1], _temp_v3, transform);
+ Vec3.set(_temp_v3, -halfWidth, -halfHeight, near);
+ Vec3.transformMat4(out.vertices[2], _temp_v3, transform);
+ Vec3.set(_temp_v3, halfWidth, -halfHeight, near);
+ Vec3.transformMat4(out.vertices[3], _temp_v3, transform);
+ Vec3.set(_temp_v3, halfWidth, halfHeight, far);
+ Vec3.transformMat4(out.vertices[4], _temp_v3, transform);
+ Vec3.set(_temp_v3, -halfWidth, halfHeight, far);
+ Vec3.transformMat4(out.vertices[5], _temp_v3, transform);
+ Vec3.set(_temp_v3, -halfWidth, -halfHeight, far);
+ Vec3.transformMat4(out.vertices[6], _temp_v3, transform);
+ Vec3.set(_temp_v3, halfWidth, -halfHeight, far);
+ Vec3.transformMat4(out.vertices[7], _temp_v3, transform);
+
+ plane.fromPoints(out.planes[0], out.vertices[1], out.vertices[6], out.vertices[5]);
+ plane.fromPoints(out.planes[1], out.vertices[3], out.vertices[4], out.vertices[7]);
+ plane.fromPoints(out.planes[2], out.vertices[6], out.vertices[3], out.vertices[7]);
+ plane.fromPoints(out.planes[3], out.vertices[0], out.vertices[5], out.vertices[4]);
+ plane.fromPoints(out.planes[4], out.vertices[2], out.vertices[0], out.vertices[3]);
+ plane.fromPoints(out.planes[0], out.vertices[7], out.vertices[5], out.vertices[6]);
+ };
+ })();
+
+ /**
+ * create a new frustum
+ * @method create
+ * @static
+ * @return {Frustum}
+ */
+ public static create () {
+ return new frustum();
+ }
+
+ /**
+ * Clone a frustum
+ * @method clone
+ * @param {Frustum} f
+ * @static
+ * @return {Frustum}
+ */
+ public static clone (f: frustum): frustum {
+ return frustum.copy(new frustum(), f);
+ }
+
+ /**
+ * Copy the values from one frustum to another
+ * @method copy
+ * @param {Frustum} out
+ * @param {Frustum} f
+ * @return {Frustum}
+ */
+ public static copy (out: frustum, f: frustum): frustum {
+ out._type = f._type;
+ for (let i = 0; i < 6; ++i) {
+ plane.copy(out.planes[i], f.planes[i]);
+ }
+ for (let i = 0; i < 8; ++i) {
+ Vec3.copy(out.vertices[i], f.vertices[i]);
+ }
+ return out;
+ }
+
+ /**
+ * @property {Plane[]} planes
+ */
+ public planes: plane[];
+ /**
+ * @property {Vec3[]} planes
+ */
+ public vertices: Vec3[];
+ private _type: number;
+
+ constructor () {
+ this._type = enums.SHAPE_FRUSTUM;
+ this.planes = new Array(6);
+ for (let i = 0; i < 6; ++i) {
+ this.planes[i] = plane.create(0, 0, 0, 0);
+ }
+ this.vertices = new Array(8);
+ for (let i = 0; i < 8; ++i) {
+ this.vertices[i] = new Vec3();
+ }
+ }
+
+ /**
+ * !#en Update the frustum information according to the given transform matrix.
+ * Note that the resulting planes are not normalized under normal mode.
+ * @method update
+ * @param {Mat4} m the view-projection matrix
+ * @param {Mat4} inv the inverse view-projection matrix
+ */
+ public update (m: Mat4, inv: Mat4) {
+ // RTR4, ch. 22.14.1, p. 983
+ // extract frustum planes from view-proj matrix.
+
+ let mm = m.m;
+
+ // left plane
+ Vec3.set(this.planes[0].n, mm[3] + mm[0], mm[7] + mm[4], mm[11] + mm[8]);
+ this.planes[0].d = -(mm[15] + mm[12]);
+ // right plane
+ Vec3.set(this.planes[1].n, mm[3] - mm[0], mm[7] - mm[4], mm[11] - mm[8]);
+ this.planes[1].d = -(mm[15] - mm[12]);
+ // bottom plane
+ Vec3.set(this.planes[2].n, mm[3] + mm[1], mm[7] + mm[5], mm[11] + mm[9]);
+ this.planes[2].d = -(mm[15] + mm[13]);
+ // top plane
+ Vec3.set(this.planes[3].n, mm[3] - mm[1], mm[7] - mm[5], mm[11] - mm[9]);
+ this.planes[3].d = -(mm[15] - mm[13]);
+ // near plane
+ Vec3.set(this.planes[4].n, mm[3] + mm[2], mm[7] + mm[6], mm[11] + mm[10]);
+ this.planes[4].d = -(mm[15] + mm[14]);
+ // far plane
+ Vec3.set(this.planes[5].n, mm[3] - mm[2], mm[7] - mm[6], mm[11] - mm[10]);
+ this.planes[5].d = -(mm[15] - mm[14]);
+
+ if (this._type !== enums.SHAPE_FRUSTUM_ACCURATE) { return; }
+
+ // normalize planes
+ for (let i = 0; i < 6; i++) {
+ const pl = this.planes[i];
+ const invDist = 1 / pl.n.length();
+ Vec3.multiplyScalar(pl.n, pl.n, invDist);
+ pl.d *= invDist;
+ }
+
+ // update frustum vertices
+ for (let i = 0; i < 8; i++) {
+ Vec3.transformMat4(this.vertices[i], _v[i], inv);
+ }
+ }
+
+ /**
+ * !#en transform by matrix
+ * @method transform
+ * @param {Mat4} mat
+ */
+ public transform (mat: Mat4) {
+ if (this._type !== enums.SHAPE_FRUSTUM_ACCURATE) {
+ return;
+ }
+ for (let i = 0; i < 8; i++) {
+ Vec3.transformMat4(this.vertices[i], this.vertices[i], mat);
+ }
+ plane.fromPoints(this.planes[0], this.vertices[1], this.vertices[5], this.vertices[6]);
+ plane.fromPoints(this.planes[1], this.vertices[3], this.vertices[7], this.vertices[4]);
+ plane.fromPoints(this.planes[2], this.vertices[6], this.vertices[7], this.vertices[3]);
+ plane.fromPoints(this.planes[3], this.vertices[0], this.vertices[4], this.vertices[5]);
+ plane.fromPoints(this.planes[4], this.vertices[2], this.vertices[3], this.vertices[0]);
+ plane.fromPoints(this.planes[0], this.vertices[7], this.vertices[6], this.vertices[5]);
+ }
+}
diff --git a/cocos2d/core/geom-utils/index.ts b/cocos2d/core/geom-utils/index.ts
new file mode 100644
index 00000000000..b035b3be487
--- /dev/null
+++ b/cocos2d/core/geom-utils/index.ts
@@ -0,0 +1,38 @@
+/****************************************************************************
+ Copyright (c) 2019 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+export { default as enums } from './enums';
+export { default as Triangle } from './triangle';
+export { default as Aabb } from './aabb';
+export { default as Ray } from './ray';
+export { default as intersect } from './intersect';
+export { default as Sphere } from './sphere';
+export { default as Obb } from './obb';
+export { default as Frustum } from './frustum';
+export { default as Line } from './line';
+export { default as Plane } from './plane';
+export * from './distance';
+
+cc.geomUtils = module.exports;
\ No newline at end of file
diff --git a/cocos2d/core/geom-utils/intersect.ts b/cocos2d/core/geom-utils/intersect.ts
new file mode 100644
index 00000000000..5ce2ad954cc
--- /dev/null
+++ b/cocos2d/core/geom-utils/intersect.ts
@@ -0,0 +1,1201 @@
+/****************************************************************************
+ Copyright (c) 2019 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import gfx from '../../renderer/gfx';
+import RecyclePool from '../../renderer/memop/recycle-pool';
+
+import { Mat3, Vec3, Mat4 } from '../value-types';
+import aabb from './aabb';
+import * as distance from './distance';
+import enums from './enums';
+import { frustum } from './frustum';
+import line from './line';
+import obb from './obb';
+import plane from './plane';
+import ray from './ray';
+import sphere from './sphere';
+import triangle from './triangle';
+
+/**
+ * @class geomUtils.intersect
+ */
+
+const ray_mesh = (function () {
+ let tri = triangle.create();
+ let minDist = Infinity;
+
+ function getVec3 (out, data, idx, stride) {
+ Vec3.set(out, data[idx*stride], data[idx*stride + 1], data[idx*stride + 2]);
+ }
+
+ return function (ray, mesh) {
+ minDist = Infinity;
+ let subMeshes = mesh._subMeshes;
+
+ for (let i = 0; i < subMeshes.length; i++) {
+ if (subMeshes[i]._primitiveType !== gfx.PT_TRIANGLES) continue;
+
+ let subData = (mesh._subDatas[i] || mesh._subDatas[0]);
+ let posData = mesh._getAttrMeshData(i, gfx.ATTR_POSITION);
+ let iData = subData.getIData(Uint16Array);
+
+ let format = subData.vfm;
+ let fmt = format.element(gfx.ATTR_POSITION);
+ let num = fmt.num;
+ for (let i = 0; i < iData.length; i += 3) {
+ getVec3(tri.a, posData, iData[ i ], num);
+ getVec3(tri.b, posData, iData[i+1], num);
+ getVec3(tri.c, posData, iData[i+2], num);
+
+ let dist = ray_triangle(ray, tri);
+ if (dist > 0 && dist < minDist) {
+ minDist = dist;
+ }
+ }
+ }
+ return minDist;
+ };
+})();
+
+// adapt to old api
+const rayMesh = ray_mesh;
+
+/**
+ * !#en
+ * Check whether ray intersect with nodes
+ * !#zh
+ * 检测射线是否与物体有交集
+ * @static
+ * @method ray_cast
+ * @param {Node} root - If root is null, then traversal nodes from scene node
+ * @param {geomUtils.Ray} worldRay
+ * @param {Function} handler
+ * @param {Function} filter
+ * @return {[]} [{node, distance}]
+*/
+const ray_cast = (function () {
+ function traversal (node, cb) {
+ var children = node.children;
+
+ for (var i = children.length - 1; i >= 0; i--) {
+ var child = children[i];
+ traversal(child, cb);
+ }
+
+ cb(node);
+ }
+
+ function cmp (a, b) {
+ return a.distance - b.distance;
+ }
+
+ function transformMat4Normal (out, a, m) {
+ let mm = m.m;
+ let x = a.x, y = a.y, z = a.z,
+ rhw = mm[3] * x + mm[7] * y + mm[11] * z;
+ rhw = rhw ? 1 / rhw : 1;
+ out.x = (mm[0] * x + mm[4] * y + mm[8] * z) * rhw;
+ out.y = (mm[1] * x + mm[5] * y + mm[9] * z) * rhw;
+ out.z = (mm[2] * x + mm[6] * y + mm[10] * z) * rhw;
+ return out;
+ }
+
+ let resultsPool = new RecyclePool(function () {
+ return {
+ distance: 0,
+ node: null
+ }
+ }, 1);
+
+ let results = [];
+
+ // temp variable
+ let nodeAabb = aabb.create();
+ let minPos = new Vec3();
+ let maxPos = new Vec3();
+
+ let modelRay = new ray();
+ let m4_1 = cc.mat4();
+ let m4_2 = cc.mat4();
+ let d = new Vec3();
+
+ function distanceValid (distance) {
+ return distance > 0 && distance < Infinity;
+ }
+
+ return function (root, worldRay, handler, filter) {
+ resultsPool.reset();
+ results.length = 0;
+
+ root = root || cc.director.getScene();
+ traversal(root, function (node) {
+ if (filter && !filter(node)) return;
+
+ // transform world ray to model ray
+ Mat4.invert(m4_2, node.getWorldMatrix(m4_1));
+ Vec3.transformMat4(modelRay.o, worldRay.o, m4_2);
+ Vec3.normalize(modelRay.d, transformMat4Normal(modelRay.d, worldRay.d, m4_2));
+
+ // raycast with bounding box
+ let distance = Infinity;
+ let component = node._renderComponent;
+ if (component instanceof cc.MeshRenderer ) {
+ distance = ray_aabb(modelRay, component._boundingBox);
+ }
+ else if (node.width && node.height) {
+ Vec3.set(minPos, -node.width * node.anchorX, -node.height * node.anchorY, node.z);
+ Vec3.set(maxPos, node.width * (1 - node.anchorX), node.height * (1 - node.anchorY), node.z);
+ aabb.fromPoints(nodeAabb, minPos, maxPos);
+ distance = ray_aabb(modelRay, nodeAabb);
+ }
+
+ if (!distanceValid(distance)) return;
+
+ if (handler) {
+ distance = handler(modelRay, node, distance);
+ }
+
+ if (distanceValid(distance)) {
+ Vec3.scale(d, modelRay.d, distance);
+ transformMat4Normal(d, d, m4_1);
+ let res = resultsPool.add();
+ res.node = node;
+ res.distance = Vec3.mag(d);
+ results.push(res);
+ }
+ });
+
+ results.sort(cmp);
+ return results;
+ }
+})();
+
+// adapt to old api
+const raycast = ray_cast;
+
+/**
+ * !#en ray-plane intersect
+ * !#zh 射线与平面的相交性检测。
+ * @static
+ * @method ray_plane
+ * @param {geomUtils.Ray} ray
+ * @param {geomUtils.Plane} plane
+ * @return {number} 0 or not 0
+ */
+const ray_plane = (function () {
+ const pt = new Vec3(0, 0, 0);
+
+ return function (ray: ray, plane: plane): number {
+ const denom = Vec3.dot(ray.d, plane.n);
+ if (Math.abs(denom) < Number.EPSILON) { return 0; }
+ Vec3.multiplyScalar(pt, plane.n, plane.d);
+ const t = Vec3.dot(Vec3.subtract(pt, pt, ray.o), plane.n) / denom;
+ if (t < 0) { return 0; }
+ return t;
+ };
+})();
+
+/**
+ * !#en line-plane intersect
+ * !#zh 线段与平面的相交性检测。
+ * @static
+ * @method line_plane
+ * @param {geomUtils.Line} line
+ * @param {geomUtils.Plane} plane
+ * @return {number} 0 or not 0
+ */
+const line_plane = (function () {
+ const ab = new Vec3(0, 0, 0);
+
+ return function (line: line, plane: plane): number {
+ Vec3.subtract(ab, line.e, line.s);
+ const t = (plane.d - Vec3.dot(line.s, plane.n)) / Vec3.dot(ab, plane.n);
+ if (t < 0 || t > 1) { return 0; }
+ return t;
+ };
+})();
+
+// based on http://fileadmin.cs.lth.se/cs/Personal/Tomas_Akenine-Moller/raytri/
+/**
+ * !#en ray-triangle intersect
+ * !#zh 射线与三角形的相交性检测。
+ * @static
+ * @method ray_triangle
+ * @param {geomUtils.Ray} ray
+ * @param {geomUtils.Triangle} triangle
+ * @param {boolean} doubleSided
+ * @return {number} 0 or not 0
+ */
+const ray_triangle = (function () {
+ const ab = new Vec3(0, 0, 0);
+ const ac = new Vec3(0, 0, 0);
+ const pvec = new Vec3(0, 0, 0);
+ const tvec = new Vec3(0, 0, 0);
+ const qvec = new Vec3(0, 0, 0);
+
+ return function (ray: ray, triangle: triangle, doubleSided?: boolean) {
+ Vec3.subtract(ab, triangle.b, triangle.a);
+ Vec3.subtract(ac, triangle.c, triangle.a);
+
+ Vec3.cross(pvec, ray.d, ac);
+ const det = Vec3.dot(ab, pvec);
+ if (det < Number.EPSILON && (!doubleSided || det > -Number.EPSILON)) { return 0; }
+
+ const inv_det = 1 / det;
+
+ Vec3.subtract(tvec, ray.o, triangle.a);
+ const u = Vec3.dot(tvec, pvec) * inv_det;
+ if (u < 0 || u > 1) { return 0; }
+
+ Vec3.cross(qvec, tvec, ab);
+ const v = Vec3.dot(ray.d, qvec) * inv_det;
+ if (v < 0 || u + v > 1) { return 0; }
+
+ const t = Vec3.dot(ac, qvec) * inv_det;
+ return t < 0 ? 0 : t;
+ };
+})();
+
+// adapt to old api
+const rayTriangle = ray_triangle;
+
+/**
+ * !#en line-triangle intersect
+ * !#zh 线段与三角形的相交性检测。
+ * @static
+ * @method line_triangle
+ * @param {geomUtils.Line} line
+ * @param {geomUtils.Triangle} triangle
+ * @param {Vec3} outPt optional, The intersection point
+ * @return {number} 0 or not 0
+ */
+const line_triangle = (function () {
+ const ab = new Vec3(0, 0, 0);
+ const ac = new Vec3(0, 0, 0);
+ const qp = new Vec3(0, 0, 0);
+ const ap = new Vec3(0, 0, 0);
+ const n = new Vec3(0, 0, 0);
+ const e = new Vec3(0, 0, 0);
+
+ return function (line: line, triangle: triangle, outPt: Vec3): number {
+ Vec3.subtract(ab, triangle.b, triangle.a);
+ Vec3.subtract(ac, triangle.c, triangle.a);
+ Vec3.subtract(qp, line.s, line.e);
+
+ Vec3.cross(n, ab, ac);
+ const det = Vec3.dot(qp, n);
+
+ if (det <= 0.0) {
+ return 0;
+ }
+
+ Vec3.subtract(ap, line.s, triangle.a);
+ const t = Vec3.dot(ap, n);
+ if (t < 0 || t > det) {
+ return 0;
+ }
+
+ Vec3.cross(e, qp, ap);
+ let v = Vec3.dot(ac, e);
+ if (v < 0 || v > det) {
+ return 0;
+ }
+
+ let w = -Vec3.dot(ab, e);
+ if (w < 0.0 || v + w > det) {
+ return 0;
+ }
+
+ if (outPt) {
+ const invDet = 1.0 / det;
+ v *= invDet;
+ w *= invDet;
+ const u = 1.0 - v - w;
+
+ // outPt = u*a + v*d + w*c;
+ Vec3.set(outPt,
+ triangle.a.x * u + triangle.b.x * v + triangle.c.x * w,
+ triangle.a.y * u + triangle.b.y * v + triangle.c.y * w,
+ triangle.a.z * u + triangle.b.z * v + triangle.c.z * w,
+ );
+ }
+
+ return 1;
+ };
+})();
+
+/**
+ * !#en line-quad intersect
+ * !#zh 线段与四边形的相交性检测。
+ * @static
+ * @method line_quad
+ * @param {Vec3} p A point on a line segment
+ * @param {Vec3} q Another point on the line segment
+ * @param {Vec3} a Quadrilateral point a
+ * @param {Vec3} b Quadrilateral point b
+ * @param {Vec3} c Quadrilateral point c
+ * @param {Vec3} d Quadrilateral point d
+ * @param {Vec3} outPt optional, The intersection point
+ * @return {number} 0 or not 0
+ */
+const line_quad = (function () {
+ const pq = new Vec3(0, 0, 0);
+ const pa = new Vec3(0, 0, 0);
+ const pb = new Vec3(0, 0, 0);
+ const pc = new Vec3(0, 0, 0);
+ const pd = new Vec3(0, 0, 0);
+ const m = new Vec3(0, 0, 0);
+ const tmp = new Vec3(0, 0, 0);
+
+ return function (p: Vec3, q: Vec3, a: Vec3, b: Vec3, c: Vec3, d: Vec3, outPt: Vec3): number {
+ Vec3.subtract(pq, q, p);
+ Vec3.subtract(pa, a, p);
+ Vec3.subtract(pb, b, p);
+ Vec3.subtract(pc, c, p);
+
+ // Determine which triangle to test against by testing against diagonal first
+ Vec3.cross(m, pc, pq);
+ let v = Vec3.dot(pa, m);
+
+ if (v >= 0) {
+ // Test intersection against triangle abc
+ let u = -Vec3.dot(pb, m);
+ if (u < 0) {
+ return 0;
+ }
+
+ let w = Vec3.dot(Vec3.cross(tmp, pq, pb), pa);
+ if (w < 0) {
+ return 0;
+ }
+
+ // outPt = u*a + v*b + w*c;
+ if (outPt) {
+ const denom = 1.0 / (u + v + w);
+ u *= denom;
+ v *= denom;
+ w *= denom;
+
+ Vec3.set(outPt,
+ a.x * u + b.x * v + c.x * w,
+ a.y * u + b.y * v + c.y * w,
+ a.z * u + b.z * v + c.z * w,
+ );
+ }
+ } else {
+ // Test intersection against triangle dac
+ Vec3.subtract(pd, d, p);
+
+ let u = Vec3.dot(pd, m);
+ if (u < 0) {
+ return 0;
+ }
+
+ let w = Vec3.dot(Vec3.cross(tmp, pq, pa), pd);
+ if (w < 0) {
+ return 0;
+ }
+
+ // outPt = u*a + v*d + w*c;
+ if (outPt) {
+ v = -v;
+
+ const denom = 1.0 / (u + v + w);
+ u *= denom;
+ v *= denom;
+ w *= denom;
+
+ Vec3.set(outPt,
+ a.x * u + d.x * v + c.x * w,
+ a.y * u + d.y * v + c.y * w,
+ a.z * u + d.z * v + c.z * w,
+ );
+ }
+ }
+
+ return 1;
+ };
+})();
+
+/**
+ * !#en ray-sphere intersect
+ * !#zh 射线和球的相交性检测。
+ * @static
+ * @method ray_sphere
+ * @param {geomUtils.Ray} ray
+ * @param {geomUtils.Sphere} sphere
+ * @return {number} 0 or not 0
+ */
+const ray_sphere = (function () {
+ const e = new Vec3(0, 0, 0);
+ return function (ray: ray, sphere: sphere): number {
+ const r = sphere.radius;
+ const c = sphere.center;
+ const o = ray.o;
+ const d = ray.d;
+ const rSq = r * r;
+ Vec3.subtract(e, c, o);
+ const eSq = e.lengthSqr();
+
+ const aLength = Vec3.dot(e, d); // assume ray direction already normalized
+ const fSq = rSq - (eSq - aLength * aLength);
+ if (fSq < 0) { return 0; }
+
+ const f = Math.sqrt(fSq);
+ const t = eSq < rSq ? aLength + f : aLength - f;
+ if (t < 0) { return 0; }
+ return t;
+ };
+})();
+
+/**
+ * !#en ray-aabb intersect
+ * !#zh 射线和轴对齐包围盒的相交性检测。
+ * @static
+ * @method ray_aabb
+ * @param {geomUtils.Ray} ray
+ * @param {geomUtils.Aabb} aabb Align the axis around the box
+ * @return {number} 0 or not 0
+ */
+const ray_aabb = (function () {
+ const min = new Vec3();
+ const max = new Vec3();
+ return function (ray: ray, aabb: aabb): number {
+ const o = ray.o, d = ray.d;
+ const ix = 1 / d.x, iy = 1 / d.y, iz = 1 / d.z;
+ Vec3.subtract(min, aabb.center, aabb.halfExtents);
+ Vec3.add(max, aabb.center, aabb.halfExtents);
+ const t1 = (min.x - o.x) * ix;
+ const t2 = (max.x - o.x) * ix;
+ const t3 = (min.y - o.y) * iy;
+ const t4 = (max.y - o.y) * iy;
+ const t5 = (min.z - o.z) * iz;
+ const t6 = (max.z - o.z) * iz;
+ const tmin = Math.max(Math.max(Math.min(t1, t2), Math.min(t3, t4)), Math.min(t5, t6));
+ const tmax = Math.min(Math.min(Math.max(t1, t2), Math.max(t3, t4)), Math.max(t5, t6));
+ if (tmax < 0 || tmin > tmax) { return 0 };
+ return tmin;
+ };
+})();
+
+// adapt to old api
+const rayAabb = ray_aabb;
+
+/**
+ * !#en ray-obb intersect
+ * !#zh 射线和方向包围盒的相交性检测。
+ * @static
+ * @method ray_obb
+ * @param {geomUtils.Ray} ray
+ * @param {geomUtils.Obb} obb Direction box
+ * @return {number} 0 or or 0
+ */
+const ray_obb = (function () {
+ let center = new Vec3();
+ let o = new Vec3();
+ let d = new Vec3();
+ const X = new Vec3();
+ const Y = new Vec3();
+ const Z = new Vec3();
+ const p = new Vec3();
+ const size = new Array(3);
+ const f = new Array(3);
+ const e = new Array(3);
+ const t = new Array(6);
+
+ return function (ray: ray, obb: obb): number {
+ size[0] = obb.halfExtents.x;
+ size[1] = obb.halfExtents.y;
+ size[2] = obb.halfExtents.z;
+ center = obb.center;
+ o = ray.o;
+ d = ray.d;
+
+ let obbm = obb.orientation.m;
+
+ Vec3.set(X, obbm[0], obbm[1], obbm[2]);
+ Vec3.set(Y, obbm[3], obbm[4], obbm[5]);
+ Vec3.set(Z, obbm[6], obbm[7], obbm[8]);
+ Vec3.subtract(p, center, o);
+
+ // The cos values of the ray on the X, Y, Z
+ f[0] = Vec3.dot(X, d);
+ f[1] = Vec3.dot(Y, d);
+ f[2] = Vec3.dot(Z, d);
+
+ // The projection length of P on X, Y, Z
+ e[0] = Vec3.dot(X, p);
+ e[1] = Vec3.dot(Y, p);
+ e[2] = Vec3.dot(Z, p);
+
+ for (let i = 0; i < 3; ++i) {
+ if (f[i] === 0) {
+ if (-e[i] - size[i] > 0 || -e[i] + size[i] < 0) {
+ return 0;
+ }
+ // Avoid div by 0!
+ f[i] = 0.0000001;
+ }
+ // min
+ t[i * 2 + 0] = (e[i] + size[i]) / f[i];
+ // max
+ t[i * 2 + 1] = (e[i] - size[i]) / f[i];
+ }
+ const tmin = Math.max(
+ Math.max(
+ Math.min(t[0], t[1]),
+ Math.min(t[2], t[3])),
+ Math.min(t[4], t[5]),
+ );
+ const tmax = Math.min(
+ Math.min(
+ Math.max(t[0], t[1]),
+ Math.max(t[2], t[3])),
+ Math.max(t[4], t[5]),
+ );
+ if (tmax < 0 || tmin > tmax || tmin < 0) {
+ return 0;
+ }
+
+ return tmin;
+ };
+})();
+
+/**
+ * !#en aabb-aabb intersect
+ * !#zh 轴对齐包围盒和轴对齐包围盒的相交性检测。
+ * @static
+ * @method aabb_aabb
+ * @param {geomUtils.Aabb} aabb1 Axis alignment surrounds box 1
+ * @param {geomUtils.Aabb} aabb2 Axis alignment surrounds box 2
+ * @return {number} 0 or not 0
+ */
+const aabb_aabb = (function () {
+ const aMin = new Vec3();
+ const aMax = new Vec3();
+ const bMin = new Vec3();
+ const bMax = new Vec3();
+ return function (aabb1: aabb, aabb2: aabb) {
+ Vec3.subtract(aMin, aabb1.center, aabb1.halfExtents);
+ Vec3.add(aMax, aabb1.center, aabb1.halfExtents);
+ Vec3.subtract(bMin, aabb2.center, aabb2.halfExtents);
+ Vec3.add(bMax, aabb2.center, aabb2.halfExtents);
+ return (aMin.x <= bMax.x && aMax.x >= bMin.x) &&
+ (aMin.y <= bMax.y && aMax.y >= bMin.y) &&
+ (aMin.z <= bMax.z && aMax.z >= bMin.z);
+ };
+})();
+
+function getAABBVertices (min: Vec3, max: Vec3, out: Vec3[]) {
+ Vec3.set(out[0], min.x, max.y, max.z);
+ Vec3.set(out[1], min.x, max.y, min.z);
+ Vec3.set(out[2], min.x, min.y, max.z);
+ Vec3.set(out[3], min.x, min.y, min.z);
+ Vec3.set(out[4], max.x, max.y, max.z);
+ Vec3.set(out[5], max.x, max.y, min.z);
+ Vec3.set(out[6], max.x, min.y, max.z);
+ Vec3.set(out[7], max.x, min.y, min.z);
+}
+
+function getOBBVertices (c: Vec3, e: Vec3, a1: Vec3, a2: Vec3, a3: Vec3, out: Vec3[]) {
+ Vec3.set(out[0],
+ c.x + a1.x * e.x + a2.x * e.y + a3.x * e.z,
+ c.y + a1.y * e.x + a2.y * e.y + a3.y * e.z,
+ c.z + a1.z * e.x + a2.z * e.y + a3.z * e.z,
+ );
+ Vec3.set(out[1],
+ c.x - a1.x * e.x + a2.x * e.y + a3.x * e.z,
+ c.y - a1.y * e.x + a2.y * e.y + a3.y * e.z,
+ c.z - a1.z * e.x + a2.z * e.y + a3.z * e.z,
+ );
+ Vec3.set(out[2],
+ c.x + a1.x * e.x - a2.x * e.y + a3.x * e.z,
+ c.y + a1.y * e.x - a2.y * e.y + a3.y * e.z,
+ c.z + a1.z * e.x - a2.z * e.y + a3.z * e.z,
+ );
+ Vec3.set(out[3],
+ c.x + a1.x * e.x + a2.x * e.y - a3.x * e.z,
+ c.y + a1.y * e.x + a2.y * e.y - a3.y * e.z,
+ c.z + a1.z * e.x + a2.z * e.y - a3.z * e.z,
+ );
+ Vec3.set(out[4],
+ c.x - a1.x * e.x - a2.x * e.y - a3.x * e.z,
+ c.y - a1.y * e.x - a2.y * e.y - a3.y * e.z,
+ c.z - a1.z * e.x - a2.z * e.y - a3.z * e.z,
+ );
+ Vec3.set(out[5],
+ c.x + a1.x * e.x - a2.x * e.y - a3.x * e.z,
+ c.y + a1.y * e.x - a2.y * e.y - a3.y * e.z,
+ c.z + a1.z * e.x - a2.z * e.y - a3.z * e.z,
+ );
+ Vec3.set(out[6],
+ c.x - a1.x * e.x + a2.x * e.y - a3.x * e.z,
+ c.y - a1.y * e.x + a2.y * e.y - a3.y * e.z,
+ c.z - a1.z * e.x + a2.z * e.y - a3.z * e.z,
+ );
+ Vec3.set(out[7],
+ c.x - a1.x * e.x - a2.x * e.y + a3.x * e.z,
+ c.y - a1.y * e.x - a2.y * e.y + a3.y * e.z,
+ c.z - a1.z * e.x - a2.z * e.y + a3.z * e.z,
+ );
+}
+
+function getInterval (vertices: any[] | Vec3[], axis: Vec3) {
+ let min = Vec3.dot(axis, vertices[0]), max = min;
+ for (let i = 1; i < 8; ++i) {
+ const projection = Vec3.dot(axis, vertices[i]);
+ min = (projection < min) ? projection : min;
+ max = (projection > max) ? projection : max;
+ }
+ return [min, max];
+}
+
+/**
+ * !#en aabb-obb intersect
+ * !#zh 轴对齐包围盒和方向包围盒的相交性检测。
+ * @static
+ * @method aabb_obb
+ * @param {geomUtils.Aabb} aabb Align the axis around the box
+ * @param {geomUtils.Obb} obb Direction box
+ * @return {number} 0 or not 0
+ */
+const aabb_obb = (function () {
+ const test = new Array(15);
+ for (let i = 0; i < 15; i++) {
+ test[i] = new Vec3(0, 0, 0);
+ }
+ const vertices = new Array(8);
+ const vertices2 = new Array(8);
+ for (let i = 0; i < 8; i++) {
+ vertices[i] = new Vec3(0, 0, 0);
+ vertices2[i] = new Vec3(0, 0, 0);
+ }
+ const min = new Vec3();
+ const max = new Vec3();
+ return function (aabb: aabb, obb: obb): number {
+ let obbm = obb.orientation.m;
+
+ Vec3.set(test[0], 1, 0, 0);
+ Vec3.set(test[1], 0, 1, 0);
+ Vec3.set(test[2], 0, 0, 1);
+ Vec3.set(test[3], obbm[0], obbm[1], obbm[2]);
+ Vec3.set(test[4], obbm[3], obbm[4], obbm[5]);
+ Vec3.set(test[5], obbm[6], obbm[7], obbm[8]);
+
+ for (let i = 0; i < 3; ++i) { // Fill out rest of axis
+ Vec3.cross(test[6 + i * 3 + 0], test[i], test[0]);
+ Vec3.cross(test[6 + i * 3 + 1], test[i], test[1]);
+ Vec3.cross(test[6 + i * 3 + 1], test[i], test[2]);
+ }
+
+ Vec3.subtract(min, aabb.center, aabb.halfExtents);
+ Vec3.add(max, aabb.center, aabb.halfExtents);
+ getAABBVertices(min, max, vertices);
+ getOBBVertices(obb.center, obb.halfExtents, test[3], test[4], test[5], vertices2);
+
+ for (let j = 0; j < 15; ++j) {
+ const a = getInterval(vertices, test[j]);
+ const b = getInterval(vertices2, test[j]);
+ if (b[0] > a[1] || a[0] > b[1]) {
+ return 0; // Seperating axis found
+ }
+ }
+
+ return 1;
+ };
+})();
+
+/**
+ * !#en aabb-plane intersect
+ * !#zh 轴对齐包围盒和平面的相交性检测。
+ * @static
+ * @method aabb_plane
+ * @param {geomUtils.Aabb} aabb Align the axis around the box
+ * @param {geomUtils.Plane} plane
+ * @return {number} inside(back) = -1, outside(front) = 0, intersect = 1
+ */
+const aabb_plane = function (aabb: aabb, plane: plane): number {
+ const r = aabb.halfExtents.x * Math.abs(plane.n.x) +
+ aabb.halfExtents.y * Math.abs(plane.n.y) +
+ aabb.halfExtents.z * Math.abs(plane.n.z);
+ const dot = Vec3.dot(plane.n, aabb.center);
+ if (dot + r < plane.d) { return -1; }
+ else if (dot - r > plane.d) { return 0; }
+ return 1;
+};
+
+/**
+ * !#en aabb-frustum intersect, faster but has false positive corner cases
+ * !#zh 轴对齐包围盒和锥台相交性检测,速度快,但有错误情况。
+ * @static
+ * @method aabb_frustum
+ * @param {geomUtils.Aabb} aabb Align the axis around the box
+ * @param {geomUtils.Frustum} frustum
+ * @return {number} 0 or not 0
+ */
+const aabb_frustum = function (aabb: aabb, frustum: frustum): number {
+ for (let i = 0; i < frustum.planes.length; i++) {
+ // frustum plane normal points to the inside
+ if (aabb_plane(aabb, frustum.planes[i]) === -1) {
+ return 0;
+ }
+ } // completely outside
+ return 1;
+};
+
+// https://cesium.com/blog/2017/02/02/tighter-frustum-culling-and-why-you-may-want-to-disregard-it/
+/**
+ * !#en aabb-frustum intersect, handles most of the false positives correctly
+ * !#zh 轴对齐包围盒和锥台相交性检测,正确处理大多数错误情况。
+ * @static
+ * @method aabb_frustum_accurate
+ * @param {geomUtils.Aabb} aabb Align the axis around the box
+ * @param {geomUtils.Frustum} frustum
+ * @return {number}
+ */
+const aabb_frustum_accurate = (function () {
+ const tmp = new Array(8);
+ let out1 = 0, out2 = 0;
+ for (let i = 0; i < tmp.length; i++) {
+ tmp[i] = new Vec3(0, 0, 0);
+ }
+ return function (aabb: aabb, frustum: frustum): number {
+ let result = 0, intersects = false;
+ // 1. aabb inside/outside frustum test
+ for (let i = 0; i < frustum.planes.length; i++) {
+ result = aabb_plane(aabb, frustum.planes[i]);
+ // frustum plane normal points to the inside
+ if (result === -1) { return 0; } // completely outside
+ else if (result === 1) { intersects = true; }
+ }
+ if (!intersects) { return 1; } // completely inside
+ // in case of false positives
+ // 2. frustum inside/outside aabb test
+ for (let i = 0; i < frustum.vertices.length; i++) {
+ Vec3.subtract(tmp[i], frustum.vertices[i], aabb.center);
+ }
+ out1 = 0, out2 = 0;
+ for (let i = 0; i < frustum.vertices.length; i++) {
+ if (tmp[i].x > aabb.halfExtents.x) { out1++; }
+ else if (tmp[i].x < -aabb.halfExtents.x) { out2++; }
+ }
+ if (out1 === frustum.vertices.length || out2 === frustum.vertices.length) { return 0; }
+ out1 = 0; out2 = 0;
+ for (let i = 0; i < frustum.vertices.length; i++) {
+ if (tmp[i].y > aabb.halfExtents.y) { out1++; }
+ else if (tmp[i].y < -aabb.halfExtents.y) { out2++; }
+ }
+ if (out1 === frustum.vertices.length || out2 === frustum.vertices.length) { return 0; }
+ out1 = 0; out2 = 0;
+ for (let i = 0; i < frustum.vertices.length; i++) {
+ if (tmp[i].z > aabb.halfExtents.z) { out1++; }
+ else if (tmp[i].z < -aabb.halfExtents.z) { out2++; }
+ }
+ if (out1 === frustum.vertices.length || out2 === frustum.vertices.length) { return 0; }
+ return 1;
+ };
+})();
+
+/**
+ * !#en obb-point intersect
+ * !#zh 方向包围盒和点的相交性检测。
+ * @static
+ * @method obb_point
+ * @param {geomUtils.Obb} obb Direction box
+ * @param {geomUtils.Vec3} point
+ * @return {boolean} true or false
+ */
+const obb_point = (function () {
+ const tmp = new Vec3(0, 0, 0), m3 = new Mat3();
+ const lessThan = function (a: Vec3, b: Vec3): boolean { return Math.abs(a.x) < b.x && Math.abs(a.y) < b.y && Math.abs(a.z) < b.z; };
+ return function (obb: obb, point: Vec3): boolean {
+ Vec3.subtract(tmp, point, obb.center);
+ Vec3.transformMat3(tmp, tmp, Mat3.transpose(m3, obb.orientation));
+ return lessThan(tmp, obb.halfExtents);
+ };
+})();
+
+/**
+ * !#en obb-plane intersect
+ * !#zh 方向包围盒和平面的相交性检测。
+ * @static
+ * @method obb_plane
+ * @param {geomUtils.Obb} obb Direction box
+ * @param {geomUtils.Plane} plane
+ * @return {number} inside(back) = -1, outside(front) = 0, intersect = 1
+ */
+const obb_plane = (function () {
+ const absDot = function (n: Vec3, x: number, y: number, z: number) {
+ return Math.abs(n.x * x + n.y * y + n.z * z);
+ };
+ return function (obb: obb, plane: plane): number {
+ let obbm = obb.orientation.m;
+ // Real-Time Collision Detection, Christer Ericson, p. 163.
+ const r = obb.halfExtents.x * absDot(plane.n, obbm[0], obbm[1], obbm[2]) +
+ obb.halfExtents.y * absDot(plane.n, obbm[3], obbm[4], obbm[5]) +
+ obb.halfExtents.z * absDot(plane.n, obbm[6], obbm[7], obbm[8]);
+
+ const dot = Vec3.dot(plane.n, obb.center);
+ if (dot + r < plane.d) { return -1; }
+ else if (dot - r > plane.d) { return 0; }
+ return 1;
+ };
+})();
+
+/**
+ * !#en obb-frustum intersect, faster but has false positive corner cases
+ * !#zh 方向包围盒和锥台相交性检测,速度快,但有错误情况。
+ * @static
+ * @method obb_frustum
+ * @param {geomUtils.Obb} obb Direction box
+ * @param {geomUtils.Frustum} frustum
+ * @return {number} 0 or not 0
+ */
+const obb_frustum = function (obb: obb, frustum: frustum): number {
+ for (let i = 0; i < frustum.planes.length; i++) {
+ // frustum plane normal points to the inside
+ if (obb_plane(obb, frustum.planes[i]) === -1) {
+ return 0;
+ }
+ } // completely outside
+ return 1;
+};
+
+// https://cesium.com/blog/2017/02/02/tighter-frustum-culling-and-why-you-may-want-to-disregard-it/
+/**
+ * !#en obb-frustum intersect, handles most of the false positives correctly
+ * !#zh 方向包围盒和锥台相交性检测,正确处理大多数错误情况。
+ * @static
+ * @method obb_frustum_accurate
+ * @param {geomUtils.Obb} obb Direction box
+ * @param {geomUtils.Frustum} frustum
+ * @return {number} 0 or not 0
+ */
+const obb_frustum_accurate = (function () {
+ const tmp = new Array(8);
+ let dist = 0, out1 = 0, out2 = 0;
+ for (let i = 0; i < tmp.length; i++) {
+ tmp[i] = new Vec3(0, 0, 0);
+ }
+ const dot = function (n: Vec3, x: number, y: number, z: number): number {
+ return n.x * x + n.y * y + n.z * z;
+ };
+ return function (obb: obb, frustum: frustum): number {
+ let result = 0, intersects = false;
+ // 1. obb inside/outside frustum test
+ for (let i = 0; i < frustum.planes.length; i++) {
+ result = obb_plane(obb, frustum.planes[i]);
+ // frustum plane normal points to the inside
+ if (result === -1) { return 0; } // completely outside
+ else if (result === 1) { intersects = true; }
+ }
+ if (!intersects) { return 1; } // completely inside
+ // in case of false positives
+ // 2. frustum inside/outside obb test
+ for (let i = 0; i < frustum.vertices.length; i++) {
+ Vec3.subtract(tmp[i], frustum.vertices[i], obb.center);
+ }
+ out1 = 0, out2 = 0;
+ let obbm = obb.orientation.m;
+ for (let i = 0; i < frustum.vertices.length; i++) {
+ dist = dot(tmp[i], obbm[0], obbm[1], obbm[2]);
+ if (dist > obb.halfExtents.x) { out1++; }
+ else if (dist < -obb.halfExtents.x) { out2++; }
+ }
+ if (out1 === frustum.vertices.length || out2 === frustum.vertices.length) { return 0; }
+ out1 = 0; out2 = 0;
+ for (let i = 0; i < frustum.vertices.length; i++) {
+ dist = dot(tmp[i], obbm[3], obbm[4], obbm[5]);
+ if (dist > obb.halfExtents.y) { out1++; }
+ else if (dist < -obb.halfExtents.y) { out2++; }
+ }
+ if (out1 === frustum.vertices.length || out2 === frustum.vertices.length) { return 0; }
+ out1 = 0; out2 = 0;
+ for (let i = 0; i < frustum.vertices.length; i++) {
+ dist = dot(tmp[i], obbm[6], obbm[7], obbm[8]);
+ if (dist > obb.halfExtents.z) { out1++; }
+ else if (dist < -obb.halfExtents.z) { out2++; }
+ }
+ if (out1 === frustum.vertices.length || out2 === frustum.vertices.length) { return 0; }
+ return 1;
+ };
+})();
+
+/**
+ * !#en obb-obb intersect
+ * !#zh 方向包围盒和方向包围盒的相交性检测。
+ * @static
+ * @method obb_obb
+ * @param {geomUtils.Obb} obb1 Direction box1
+ * @param {geomUtils.Obb} obb2 Direction box2
+ * @return {number} 0 or not 0
+ */
+const obb_obb = (function () {
+ const test = new Array(15);
+ for (let i = 0; i < 15; i++) {
+ test[i] = new Vec3(0, 0, 0);
+ }
+
+ const vertices = new Array(8);
+ const vertices2 = new Array(8);
+ for (let i = 0; i < 8; i++) {
+ vertices[i] = new Vec3(0, 0, 0);
+ vertices2[i] = new Vec3(0, 0, 0);
+ }
+
+ return function (obb1: obb, obb2: obb): number {
+
+ let obb1m = obb1.orientation.m;
+ let obb2m = obb2.orientation.m;
+
+ Vec3.set(test[0], obb1m[0], obb1m[1], obb1m[2]);
+ Vec3.set(test[1], obb1m[3], obb1m[4], obb1m[5]);
+ Vec3.set(test[2], obb1m[6], obb1m[7], obb1m[8]);
+ Vec3.set(test[3], obb2m[0], obb2m[1], obb2m[2]);
+ Vec3.set(test[4], obb2m[3], obb2m[4], obb2m[5]);
+ Vec3.set(test[5], obb2m[6], obb2m[7], obb2m[8]);
+
+ for (let i = 0; i < 3; ++i) { // Fill out rest of axis
+ Vec3.cross(test[6 + i * 3 + 0], test[i], test[0]);
+ Vec3.cross(test[6 + i * 3 + 1], test[i], test[1]);
+ Vec3.cross(test[6 + i * 3 + 1], test[i], test[2]);
+ }
+
+ getOBBVertices(obb1.center, obb1.halfExtents, test[0], test[1], test[2], vertices);
+ getOBBVertices(obb2.center, obb2.halfExtents, test[3], test[4], test[5], vertices2);
+
+ for (let i = 0; i < 15; ++i) {
+ const a = getInterval(vertices, test[i]);
+ const b = getInterval(vertices2, test[i]);
+ if (b[0] > a[1] || a[0] > b[1]) {
+ return 0; // Seperating axis found
+ }
+ }
+
+ return 1;
+ };
+})();
+
+/**
+ * !#en phere-plane intersect, not necessarily faster than obb-plane
+ * due to the length calculation of the plane normal to factor out
+ * the unnomalized plane distance
+ * !#zh 球与平面的相交性检测。
+ * @static
+ * @method sphere_plane
+ * @param {geomUtils.Sphere} sphere
+ * @param {geomUtils.Plane} plane
+ * @return {number} inside(back) = -1, outside(front) = 0, intersect = 1
+ */
+const sphere_plane = function (sphere: sphere, plane: plane): number {
+ const dot = Vec3.dot(plane.n, sphere.center);
+ const r = sphere.radius * plane.n.length();
+ if (dot + r < plane.d) { return -1; }
+ else if (dot - r > plane.d) { return 0; }
+ return 1;
+};
+
+/**
+ * !#en sphere-frustum intersect, faster but has false positive corner cases
+ * !#zh 球和锥台的相交性检测,速度快,但有错误情况。
+ * @static
+ * @method sphere_frustum
+ * @param {geomUtils.Sphere} sphere
+ * @param {geomUtils.Frustum} frustum
+ * @return {number} 0 or not 0
+ */
+const sphere_frustum = function (sphere: sphere, frustum: frustum): number {
+ for (let i = 0; i < frustum.planes.length; i++) {
+ // frustum plane normal points to the inside
+ if (sphere_plane(sphere, frustum.planes[i]) === -1) {
+ return 0;
+ }
+ } // completely outside
+ return 1;
+};
+
+// https://stackoverflow.com/questions/20912692/view-frustum-culling-corner-cases
+/**
+ * !#en sphere-frustum intersect, handles the false positives correctly
+ * !#zh 球和锥台的相交性检测,正确处理大多数错误情况。
+ * @static
+ * @method sphere_frustum_accurate
+ * @param {geomUtils.Sphere} sphere
+ * @param {geomUtils.Frustum} frustum
+ * @return {number} 0 or not 0
+ */
+const sphere_frustum_accurate = (function () {
+ const pt = new Vec3(0, 0, 0), map = [1, -1, 1, -1, 1, -1];
+ return function (sphere: sphere, frustum: frustum): number {
+ for (let i = 0; i < 6; i++) {
+ const plane = frustum.planes[i];
+ const r = sphere.radius, c = sphere.center;
+ const n = plane.n, d = plane.d;
+ const dot = Vec3.dot(n, c);
+ // frustum plane normal points to the inside
+ if (dot + r < d) { return 0; } // completely outside
+ else if (dot - r > d) { continue; }
+ // in case of false positives
+ // has false negatives, still working on it
+ Vec3.add(pt, c, Vec3.multiplyScalar(pt, n, r));
+ for (let j = 0; j < 6; j++) {
+ if (j === i || j === i + map[i]) { continue; }
+ const test = frustum.planes[j];
+ if (Vec3.dot(test.n, pt) < test.d) { return 0; }
+ }
+ }
+ return 1;
+ };
+})();
+
+/**
+ * !#en sphere-sphere intersect
+ * !#zh 球和球的相交性检测。
+ * @static
+ * @method sphere_sphere
+ * @param {geomUtils.Sphere} sphere0
+ * @param {geomUtils.Sphere} sphere1
+ * @return {boolean} true or false
+ */
+const sphere_sphere = function (sphere0: sphere, sphere1: sphere): boolean {
+ const r = sphere0.radius + sphere1.radius;
+ return Vec3.squaredDistance(sphere0.center, sphere1.center) < r * r;
+};
+
+/**
+ * !#en sphere-aabb intersect
+ * !#zh 球和轴对齐包围盒的相交性检测。
+ * @static
+ * @method sphere_aabb
+ * @param {geomUtils.Sphere} sphere
+ * @param {geomUtils.Aabb} aabb
+ * @return {boolean} true or false
+ */
+const sphere_aabb = (function () {
+ const pt = new Vec3();
+ return function (sphere: sphere, aabb: aabb): boolean {
+ distance.pt_point_aabb(pt, sphere.center, aabb);
+ return Vec3.squaredDistance(sphere.center, pt) < sphere.radius * sphere.radius;
+ };
+})();
+
+/**
+ * !#en sphere-obb intersect
+ * !#zh 球和方向包围盒的相交性检测。
+ * @static
+ * @method sphere_obb
+ * @param {geomUtils.Sphere} sphere
+ * @param {geomUtils.Obb} obb
+ * @return {boolean} true or false
+ */
+const sphere_obb = (function () {
+ const pt = new Vec3();
+ return function (sphere: sphere, obb: obb): boolean {
+ distance.pt_point_obb(pt, sphere.center, obb);
+ return Vec3.squaredDistance(sphere.center, pt) < sphere.radius * sphere.radius;
+ };
+})();
+
+const intersect = {
+ // old api
+ rayAabb,
+ rayMesh,
+ raycast,
+ rayTriangle,
+
+ ray_sphere,
+ ray_aabb,
+ ray_obb,
+ ray_plane,
+ ray_triangle,
+ line_plane,
+ line_triangle,
+ line_quad,
+
+ sphere_sphere,
+ sphere_aabb,
+ sphere_obb,
+ sphere_plane,
+ sphere_frustum,
+ sphere_frustum_accurate,
+
+ aabb_aabb,
+ aabb_obb,
+ aabb_plane,
+ aabb_frustum,
+ aabb_frustum_accurate,
+
+ obb_obb,
+ obb_plane,
+ obb_frustum,
+ obb_frustum_accurate,
+ obb_point,
+
+ /**
+ * !#en
+ * The intersection detection of g1 and g2 can fill in the shape in the basic geometry.
+ * !#zh
+ * g1 和 g2 的相交性检测,可填入基础几何中的形状。
+ * @static
+ * @method resolve
+ * @param g1 Geometry 1
+ * @param g2 Geometry 2
+ * @param outPt optional, Intersection point. (note: only partial shape detection with this return value)
+ */
+ resolve (g1: any, g2: any, outPt = null) {
+ const type1 = g1._type, type2 = g2._type;
+ const resolver = this[type1 | type2];
+ if (type1 < type2) { return resolver(g1, g2, outPt); }
+ else { return resolver(g2, g1, outPt); }
+ },
+};
+
+intersect[enums.SHAPE_RAY | enums.SHAPE_SPHERE] = ray_sphere;
+intersect[enums.SHAPE_RAY | enums.SHAPE_AABB] = ray_aabb;
+intersect[enums.SHAPE_RAY | enums.SHAPE_OBB] = ray_obb;
+intersect[enums.SHAPE_RAY | enums.SHAPE_PLANE] = ray_plane;
+intersect[enums.SHAPE_RAY | enums.SHAPE_TRIANGLE] = ray_triangle;
+intersect[enums.SHAPE_LINE | enums.SHAPE_PLANE] = line_plane;
+intersect[enums.SHAPE_LINE | enums.SHAPE_TRIANGLE] = line_triangle;
+
+intersect[enums.SHAPE_SPHERE] = sphere_sphere;
+intersect[enums.SHAPE_SPHERE | enums.SHAPE_AABB] = sphere_aabb;
+intersect[enums.SHAPE_SPHERE | enums.SHAPE_OBB] = sphere_obb;
+intersect[enums.SHAPE_SPHERE | enums.SHAPE_PLANE] = sphere_plane;
+intersect[enums.SHAPE_SPHERE | enums.SHAPE_FRUSTUM] = sphere_frustum;
+intersect[enums.SHAPE_SPHERE | enums.SHAPE_FRUSTUM_ACCURATE] = sphere_frustum_accurate;
+
+intersect[enums.SHAPE_AABB] = aabb_aabb;
+intersect[enums.SHAPE_AABB | enums.SHAPE_OBB] = aabb_obb;
+intersect[enums.SHAPE_AABB | enums.SHAPE_PLANE] = aabb_plane;
+intersect[enums.SHAPE_AABB | enums.SHAPE_FRUSTUM] = aabb_frustum;
+intersect[enums.SHAPE_AABB | enums.SHAPE_FRUSTUM_ACCURATE] = aabb_frustum_accurate;
+
+intersect[enums.SHAPE_OBB] = obb_obb;
+intersect[enums.SHAPE_OBB | enums.SHAPE_PLANE] = obb_plane;
+intersect[enums.SHAPE_OBB | enums.SHAPE_FRUSTUM] = obb_frustum;
+intersect[enums.SHAPE_OBB | enums.SHAPE_FRUSTUM_ACCURATE] = obb_frustum_accurate;
+
+export default intersect;
diff --git a/cocos2d/core/geom-utils/line.ts b/cocos2d/core/geom-utils/line.ts
new file mode 100644
index 00000000000..87be36fcbd0
--- /dev/null
+++ b/cocos2d/core/geom-utils/line.ts
@@ -0,0 +1,192 @@
+/****************************************************************************
+ Copyright (c) 2019 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+import { Vec3 } from '../value-types';
+import enums from './enums';
+
+/**
+ * !#en
+ * line
+ * !#zh
+ * 直线
+ * @class geomUtils.Line
+ */
+export default class line {
+
+ /**
+ * !#en
+ * create a new line
+ * !#zh
+ * 创建一个新的 line。
+ * @method create
+ * @param {Number} sx The x part of the starting point.
+ * @param {Number} sy The y part of the starting point.
+ * @param {Number} sz The z part of the starting point.
+ * @param {Number} ex The x part of the end point.
+ * @param {Number} ey The y part of the end point.
+ * @param {Number} ez The z part of the end point.
+ * @return {Line}
+ */
+ public static create (sx: number, sy: number, sz: number, ex: number, ey: number, ez: number) {
+ return new line(sx, sy, sz, ex, ey, ez);
+ }
+
+ /**
+ * !#en
+ * Creates a new line initialized with values from an existing line
+ * !#zh
+ * 克隆一个新的 line。
+ * @method clone
+ * @param {Line} a The source of cloning.
+ * @return {Line} The cloned object.
+ */
+ public static clone (a: line) {
+ return new line(
+ a.s.x, a.s.y, a.s.z,
+ a.e.x, a.e.y, a.e.z,
+ );
+ }
+
+ /**
+ * !#en
+ * Copy the values from one line to another
+ * !#zh
+ * 复制一个线的值到另一个。
+ * @method copy
+ * @param {Line} out The object that accepts the action.
+ * @param {Line} a The source of the copy.
+ * @return {Line} The object that accepts the action.
+ */
+ public static copy (out: line, a: line) {
+ Vec3.copy(out.s, a.s);
+ Vec3.copy(out.e, a.e);
+
+ return out;
+ }
+
+ /**
+ * !#en
+ * create a line from two points
+ * !#zh
+ * 用两个点创建一个线。
+ * @method fromPoints
+ * @param {Line} out The object that accepts the action.
+ * @param {Vec3} start The starting point.
+ * @param {Vec3} end At the end.
+ * @return {Line} out The object that accepts the action.
+ */
+ public static fromPoints (out: line, start: Vec3, end: Vec3) {
+ Vec3.copy(out.s, start);
+ Vec3.copy(out.e, end);
+ return out;
+ }
+
+ /**
+ * !#en
+ * Set the components of a Vec3 to the given values
+ * !#zh
+ * 将给定线的属性设置为给定值。
+ * @method set
+ * @param {Line} out The object that accepts the action.
+ * @param {Number} sx The x part of the starting point.
+ * @param {Number} sy The y part of the starting point.
+ * @param {Number} sz The z part of the starting point.
+ * @param {Number} ex The x part of the end point.
+ * @param {Number} ey The y part of the end point.
+ * @param {Number} ez The z part of the end point.
+ * @return {Line} out The object that accepts the action.
+ */
+ public static set (out: line, sx: number, sy: number, sz: number, ex: number, ey: number, ez: number) {
+ out.s.x = sx;
+ out.s.y = sy;
+ out.s.z = sz;
+ out.e.x = ex;
+ out.e.y = ey;
+ out.e.z = ez;
+
+ return out;
+ }
+
+ /**
+ * !#en
+ * Calculate the length of the line.
+ * !#zh
+ * 计算线的长度。
+ * @method len
+ * @param {Line} a The line to calculate.
+ * @return {Number} Length.
+ */
+ public static len (a: line) {
+ return Vec3.distance(a.s, a.e);
+ }
+
+ /**
+ * !#en
+ * Start points.
+ * !#zh
+ * 起点。
+ * @property {Vec3} s
+ */
+ public s: Vec3;
+
+ /**
+ * !#en
+ * End points.
+ * !#zh
+ * 终点。
+ * @property {Vec3} e
+ */
+ public e: Vec3;
+
+ private _type: number;
+
+ /**
+ * !#en Construct a line.
+ * !#zh 构造一条线。
+ * @constructor
+ * @param {Number} sx The x part of the starting point.
+ * @param {Number} sy The y part of the starting point.
+ * @param {Number} sz The z part of the starting point.
+ * @param {Number} ex The x part of the end point.
+ * @param {Number} ey The y part of the end point.
+ * @param {Number} ez The z part of the end point.
+ */
+ constructor (sx = 0, sy = 0, sz = 0, ex = 0, ey = 0, ez = -1) {
+ this._type = enums.SHAPE_LINE;
+ this.s = new Vec3(sx, sy, sz);
+ this.e = new Vec3(ex, ey, ez);
+ }
+
+ /**
+ * !#en
+ * Calculate the length of the line.
+ * !#zh
+ * 计算线的长度。
+ * @method length
+ * @return {Number} Length.
+ */
+ public length () {
+ return Vec3.distance(this.s, this.e);
+ }
+}
diff --git a/cocos2d/core/geom-utils/obb.ts b/cocos2d/core/geom-utils/obb.ts
new file mode 100644
index 00000000000..862e3f7b02d
--- /dev/null
+++ b/cocos2d/core/geom-utils/obb.ts
@@ -0,0 +1,283 @@
+/****************************************************************************
+ Copyright (c) 2019 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import { Mat3, Mat4, Quat, Vec3 } from '../value-types';
+import enums from './enums';
+
+const _v3_tmp = new Vec3();
+const _v3_tmp2 = new Vec3();
+const _m3_tmp = new Mat3();
+
+// https://zeuxcg.org/2010/10/17/aabb-from-obb-with-component-wise-abs/
+const transform_extent_m3 = (out: Vec3, extent: Vec3, m3: Mat3) => {
+ let m3_tmpm = _m3_tmp.m, m3m = m3.m;
+ m3_tmpm[0] = Math.abs(m3m[0]); m3_tmpm[1] = Math.abs(m3m[1]); m3_tmpm[2] = Math.abs(m3m[2]);
+ m3_tmpm[3] = Math.abs(m3m[3]); m3_tmpm[4] = Math.abs(m3m[4]); m3_tmpm[5] = Math.abs(m3m[5]);
+ m3_tmpm[6] = Math.abs(m3m[6]); m3_tmpm[7] = Math.abs(m3m[7]); m3_tmpm[8] = Math.abs(m3m[8]);
+ Vec3.transformMat3(out, extent, _m3_tmp);
+};
+
+/**
+ * !#en obb
+ * !#zh
+ * 基础几何 方向包围盒。
+ * @class geomUtils.Obb
+ */
+export default class obb {
+
+ /**
+ * !#zh
+ * 获取形状的类型。
+ * @property {number} type
+ * @readonly
+ */
+ get type () {
+ return this._type;
+ }
+
+ /**
+ * !#en
+ * create a new obb
+ * !#zh
+ * 创建一个新的 obb 实例。
+ * @method create
+ * @param {Number} cx X coordinates of the shape relative to the origin.
+ * @param {Number} cy Y coordinates of the shape relative to the origin.
+ * @param {Number} cz Z coordinates of the shape relative to the origin.
+ * @param {Number} hw Obb is half the width.
+ * @param {Number} hh Obb is half the height.
+ * @param {Number} hl Obb is half the Length.
+ * @param {Number} ox_1 Direction matrix parameter.
+ * @param {Number} ox_2 Direction matrix parameter.
+ * @param {Number} ox_3 Direction matrix parameter.
+ * @param {Number} oy_1 Direction matrix parameter.
+ * @param {Number} oy_2 Direction matrix parameter.
+ * @param {Number} oy_3 Direction matrix parameter.
+ * @param {Number} oz_1 Direction matrix parameter.
+ * @param {Number} oz_2 Direction matrix parameter.
+ * @param {Number} oz_3 Direction matrix parameter.
+ * @return {Obb} Direction Box.
+ */
+ public static create (
+ cx: number, cy: number, cz: number,
+ hw: number, hh: number, hl: number,
+ ox_1: number, ox_2: number, ox_3: number,
+ oy_1: number, oy_2: number, oy_3: number,
+ oz_1: number, oz_2: number, oz_3: number) {
+ return new obb(cx, cy, cz, hw, hh, hl, ox_1, ox_2, ox_3, oy_1, oy_2, oy_3, oz_1, oz_2, oz_3);
+ }
+
+ /**
+ * !#en
+ * clone a new obb
+ * !#zh
+ * 克隆一个 obb。
+ * @method clone
+ * @param {Obb} a The target of cloning.
+ * @returns {Obb} New object cloned.
+ */
+ public static clone (a: obb) {
+ let aom = a.orientation.m;
+ return new obb(a.center.x, a.center.y, a.center.z,
+ a.halfExtents.x, a.halfExtents.y, a.halfExtents.z,
+ aom[0], aom[1], aom[2],
+ aom[3], aom[4], aom[5],
+ aom[6], aom[7], aom[8]);
+ }
+
+ /**
+ * !#en
+ * copy the values from one obb to another
+ * !#zh
+ * 将从一个 obb 的值复制到另一个 obb。
+ * @method copy
+ * @param {Obb} out Obb that accepts the operation.
+ * @param {Obb} a Obb being copied.
+ * @return {Obb} out Obb that accepts the operation.
+ */
+ public static copy (out: obb, a: obb): obb {
+ Vec3.copy(out.center, a.center);
+ Vec3.copy(out.halfExtents, a.halfExtents);
+ Mat3.copy(out.orientation, a.orientation);
+
+ return out;
+ }
+
+ /**
+ * !#en
+ * create a new obb from two corner points
+ * !#zh
+ * 用两个点创建一个新的 obb。
+ * @method fromPoints
+ * @param {Obb} out Obb that accepts the operation.
+ * @param {Vec3} minPos The smallest point of obb.
+ * @param {Vec3} maxPos Obb's maximum point.
+ * @returns {Obb} out Obb that accepts the operation.
+ */
+ public static fromPoints (out: obb, minPos: Vec3, maxPos: Vec3): obb {
+ Vec3.multiplyScalar(out.center, Vec3.add(_v3_tmp, minPos, maxPos), 0.5);
+ Vec3.multiplyScalar(out.halfExtents, Vec3.subtract(_v3_tmp2, maxPos, minPos), 0.5);
+ Mat3.identity(out.orientation);
+ return out;
+ }
+
+ /**
+ * !#en
+ * Set the components of a obb to the given values
+ * !#zh
+ * 将给定 obb 的属性设置为给定的值。
+ * @method set
+ * @param {Number} cx X coordinates of the shape relative to the origin.
+ * @param {Number} cy Y coordinates of the shape relative to the origin.
+ * @param {Number} cz Z coordinates of the shape relative to the origin.
+ * @param {Number} hw Obb is half the width.
+ * @param {Number} hh Obb is half the height.
+ * @param {Number} hl Obb is half the Length.
+ * @param {Number} ox_1 Direction matrix parameter.
+ * @param {Number} ox_2 Direction matrix parameter.
+ * @param {Number} ox_3 Direction matrix parameter.
+ * @param {Number} oy_1 Direction matrix parameter.
+ * @param {Number} oy_2 Direction matrix parameter.
+ * @param {Number} oy_3 Direction matrix parameter.
+ * @param {Number} oz_1 Direction matrix parameter.
+ * @param {Number} oz_2 Direction matrix parameter.
+ * @param {Number} oz_3 Direction matrix parameter.
+ * @return {Obb} out
+ */
+ public static set (
+ out: obb,
+ cx: number, cy: number, cz: number,
+ hw: number, hh: number, hl: number,
+ ox_1: number, ox_2: number, ox_3: number,
+ oy_1: number, oy_2: number, oy_3: number,
+ oz_1: number, oz_2: number, oz_3: number): obb {
+ Vec3.set(out.center, cx, cy, cz);
+ Vec3.set(out.halfExtents, hw, hh, hl);
+ Mat3.set(out.orientation, ox_1, ox_2, ox_3, oy_1, oy_2, oy_3, oz_1, oz_2, oz_3);
+ return out;
+ }
+
+ /**
+ * !#en
+ * The center of the local coordinate.
+ * !#zh
+ * 本地坐标的中心点。
+ * @property {Vec3} center
+ */
+ public center: Vec3;
+
+ /**
+ * !#en
+ * Half the length, width, and height.
+ * !#zh
+ * 长宽高的一半。
+ * @property {Vec3} halfExtents
+ */
+ public halfExtents: Vec3;
+
+ /**
+ * !#en
+ * Direction matrix.
+ * !#zh
+ * 方向矩阵。
+ * @property {Mat3} orientation
+ */
+ public orientation: Mat3;
+
+ protected _type: number;
+
+ constructor (cx = 0, cy = 0, cz = 0,
+ hw = 1, hh = 1, hl = 1,
+ ox_1 = 1, ox_2 = 0, ox_3 = 0,
+ oy_1 = 0, oy_2 = 1, oy_3 = 0,
+ oz_1 = 0, oz_2 = 0, oz_3 = 1) {
+ this._type = enums.SHAPE_OBB;
+ this.center = new Vec3(cx, cy, cz);
+ this.halfExtents = new Vec3(hw, hh, hl);
+ this.orientation = new Mat3(ox_1, ox_2, ox_3, oy_1, oy_2, oy_3, oz_1, oz_2, oz_3);
+ }
+
+ /**
+ * !#en
+ * Get the bounding points of this shape
+ * !#zh
+ * 获取 obb 的最小点和最大点。
+ * @method getBoundary
+ * @param {Vec3} minPos
+ * @param {Vec3} maxPos
+ */
+ public getBoundary (minPos: Vec3, maxPos: Vec3) {
+ transform_extent_m3(_v3_tmp, this.halfExtents, this.orientation);
+ Vec3.subtract(minPos, this.center, _v3_tmp);
+ Vec3.add(maxPos, this.center, _v3_tmp);
+ }
+
+ /**
+ * !#en Transform this shape
+ * !#zh
+ * 将 out 根据这个 obb 的数据进行变换。
+ * @method transform
+ * @param {Mat4} m The transformation matrix.
+ * @param {Vec3} pos The position part of the transformation.
+ * @param {Quat} rot The rotating part of the transformation.
+ * @param {Vec3} scale The scaling part of the transformation.
+ * @param {Obb} out Target of transformation.
+ */
+ public transform (m: Mat4, pos: Vec3, rot: Quat, scale: Vec3, out: obb) {
+ Vec3.transformMat4(out.center, this.center, m);
+ // parent shape doesn't contain rotations for now
+ Mat3.fromQuat(out.orientation, rot);
+ Vec3.multiply(out.halfExtents, this.halfExtents, scale);
+ }
+
+ /**
+ * !#en
+ * Transform out based on this obb data.
+ * !#zh
+ * 将 out 根据这个 obb 的数据进行变换。
+ * @method translateAndRotate
+ * @param {Mat4} m The transformation matrix.
+ * @param {Quat} rot The rotating part of the transformation.
+ * @param {Obb} out Target of transformation.
+ */
+ public translateAndRotate (m: Mat4, rot: Quat, out: obb){
+ Vec3.transformMat4(out.center, this.center, m);
+ // parent shape doesn't contain rotations for now
+ Mat3.fromQuat(out.orientation, rot);
+ }
+
+ /**
+ * !#en
+ * Scale out based on this obb data.
+ * !#zh
+ * 将 out 根据这个 obb 的数据进行缩放。
+ * @method setScale
+ * @param {Vec3} scale Scale value.
+ * @param {Obb} out Scaled target.
+ */
+ public setScale (scale: Vec3, out: obb) {
+ Vec3.multiply(out.halfExtents, this.halfExtents, scale);
+ }
+}
diff --git a/cocos2d/core/geom-utils/plane.ts b/cocos2d/core/geom-utils/plane.ts
new file mode 100644
index 00000000000..c33180f544c
--- /dev/null
+++ b/cocos2d/core/geom-utils/plane.ts
@@ -0,0 +1,221 @@
+/****************************************************************************
+ Copyright (c) 2019 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import { Mat4, Vec3, Vec4 } from '../value-types';
+import enums from './enums';
+
+const v1 = new Vec3(0, 0, 0);
+const v2 = new Vec3(0, 0, 0);
+const temp_mat = cc.mat4();
+const temp_vec4 = cc.v4();
+
+/**
+ * !#en
+ * plane。
+ * !#zh
+ * 平面。
+ * @class geomUtils.Plane
+ */
+export default class plane {
+
+ /**
+ * !#en
+ * create a new plane
+ * !#zh
+ * 创建一个新的 plane。
+ * @method create
+ * @param {Number} nx The x part of the normal component.
+ * @param {Number} ny The y part of the normal component.
+ * @param {Number} nz The z part of the normal component.
+ * @param {Number} d Distance from the origin.
+ * @return {Plane}
+ */
+ public static create (nx: number, ny: number, nz: number, d: number) {
+ return new plane(nx, ny, nz, d);
+ }
+
+ /**
+ * !#en
+ * clone a new plane
+ * !#zh
+ * 克隆一个新的 plane。
+ * @method clone
+ * @param {Plane} p The source of cloning.
+ * @return {Plane} The cloned object.
+ */
+ public static clone (p: plane) {
+ return new plane(p.n.x, p.n.y, p.n.z, p.d);
+ }
+
+ /**
+ * !#en
+ * copy the values from one plane to another
+ * !#zh
+ * 复制一个平面的值到另一个。
+ * @method copy
+ * @param {Plane} out The object that accepts the action.
+ * @param {Plane} p The source of the copy.
+ * @return {Plane} The object that accepts the action.
+ */
+ public static copy (out: plane, p: plane) {
+ Vec3.copy(out.n, p.n);
+ out.d = p.d;
+
+ return out;
+ }
+
+ /**
+ * !#en
+ * create a plane from three points
+ * !#zh
+ * 用三个点创建一个平面。
+ * @method fromPoints
+ * @param {Plane} out The object that accepts the action.
+ * @param {Vec3} a Point a。
+ * @param {Vec3} b Point b。
+ * @param {Vec3} c Point c。
+ * @return {Plane} out The object that accepts the action.
+ */
+ public static fromPoints (out: plane, a: Vec3, b: Vec3, c: Vec3) {
+ Vec3.subtract(v1, b, a);
+ Vec3.subtract(v2, c, a);
+
+ Vec3.normalize(out.n, Vec3.cross(out.n, v1, v2));
+ out.d = Vec3.dot(out.n, a);
+
+ return out;
+ }
+
+ /**
+ * !#en
+ * Set the components of a plane to the given values
+ * !#zh
+ * 将给定平面的属性设置为给定值。
+ * @method set
+ * @param {Plane} out The object that accepts the action.
+ * @param {Number} nx The x part of the normal component.
+ * @param {Number} ny The y part of the normal component.
+ * @param {Number} nz The z part of the normal component.
+ * @param {Number} d Distance from the origin.
+ * @return {Plane} out The object that accepts the action.
+ */
+ public static set (out: plane, nx: number, ny: number, nz: number, d: number) {
+ out.n.x = nx;
+ out.n.y = ny;
+ out.n.z = nz;
+ out.d = d;
+
+ return out;
+ }
+
+ /**
+ * !#en
+ * create plane from normal and point
+ * !#zh
+ * 用一条法线和一个点创建平面。
+ * @method fromNormalAndPoint
+ * @param {Plane} out The object that accepts the action.
+ * @param {Vec3} normal The normal of a plane.
+ * @param {Vec3} point A point on the plane.
+ * @return {Plane} out The object that accepts the action.
+ */
+ public static fromNormalAndPoint (out: plane, normal: Vec3, point: Vec3) {
+ Vec3.copy(out.n, normal);
+ out.d = Vec3.dot(normal, point);
+
+ return out;
+ }
+
+ /**
+ * !#en
+ * normalize a plane
+ * !#zh
+ * 归一化一个平面。
+ * @method normalize
+ * @param {Plane} out The object that accepts the action.
+ * @param {Plane} a Source data for operations.
+ * @return {Plane} out The object that accepts the action.
+ */
+ public static normalize (out: plane, a: plane) {
+ const len = a.n.len();
+ Vec3.normalize(out.n, a.n);
+ if (len > 0) {
+ out.d = a.d / len;
+ }
+ return out;
+ }
+
+ /**
+ * !#en
+ * A normal vector.
+ * !#zh
+ * 法线向量。
+ * @property {Vec3} n
+ */
+ public n: Vec3;
+
+ /**
+ * !#en
+ * The distance from the origin to the plane.
+ * !#zh
+ * 原点到平面的距离。
+ * @property {number} d
+ */
+ public d: number;
+
+ private _type: number;
+
+ /**
+ * !#en Construct a plane.
+ * !#zh 构造一个平面。
+ * @constructor
+ * @param {Number} nx The x part of the normal component.
+ * @param {Number} ny The y part of the normal component.
+ * @param {Number} nz The z part of the normal component.
+ * @param {Number} d Distance from the origin.
+ */
+ constructor (nx = 0, ny = 1, nz = 0, d = 0) {
+ this._type = enums.SHAPE_PLANE;
+ this.n = new Vec3(nx, ny, nz);
+ this.d = d;
+ }
+
+ /**
+ * !#en
+ * Transform a plane.
+ * !#zh
+ * 变换一个平面。
+ * @method transform
+ * @param {Mat4} mat
+ */
+ public transform (mat: Mat4): void {
+ Mat4.invert(temp_mat, mat);
+ Mat4.transpose(temp_mat, temp_mat);
+ Vec4.set(temp_vec4, this.n.x, this.n.y, this.n.z, this.d);
+ Vec4.transformMat4(temp_vec4, temp_vec4, temp_mat);
+ Vec3.set(this.n, temp_vec4.x, temp_vec4.y, temp_vec4.z);
+ this.d = temp_vec4.w;
+ }
+}
diff --git a/cocos2d/core/geom-utils/ray.ts b/cocos2d/core/geom-utils/ray.ts
new file mode 100644
index 00000000000..d2c7f12e561
--- /dev/null
+++ b/cocos2d/core/geom-utils/ray.ts
@@ -0,0 +1,181 @@
+/****************************************************************************
+ Copyright (c) 2019 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import { Vec3 } from '../value-types';
+import enums from './enums';
+import { IVec3Like } from '../value-types/math';
+
+/**
+ * !#en
+ * ray
+ * !#zh
+ * 射线。
+ * @class geomUtils.Ray
+ */
+export default class ray {
+
+ /**
+ * !#en
+ * create a new ray
+ * !#zh
+ * 创建一条射线。
+ * @method create
+ * @param {number} ox The x part of the starting point.
+ * @param {number} oy The y part of the starting point.
+ * @param {number} oz The z part of the starting point.
+ * @param {number} dx X in the direction.
+ * @param {number} dy Y in the direction.
+ * @param {number} dz Z in the direction.
+ * @return {Ray}
+ */
+ public static create (ox: number = 0, oy: number = 0, oz: number = 0, dx: number = 0, dy: number = 0, dz: number = 1): ray {
+ return new ray(ox, oy, oz, dx, dy, dz);
+ }
+
+ /**
+ * !#en
+ * Creates a new ray initialized with values from an existing ray
+ * !#zh
+ * 从一条射线克隆出一条新的射线。
+ * @method clone
+ * @param {Ray} a Clone target
+ * @return {Ray} Clone result
+ */
+ public static clone (a: ray): ray {
+ return new ray(
+ a.o.x, a.o.y, a.o.z,
+ a.d.x, a.d.y, a.d.z,
+ );
+ }
+
+ /**
+ * !#en
+ * Copy the values from one ray to another
+ * !#zh
+ * 将从一个 ray 的值复制到另一个 ray。
+ * @method copy
+ * @param {Ray} out Accept the ray of the operation.
+ * @param {Ray} a Copied ray.
+ * @return {Ray} out Accept the ray of the operation.
+ */
+ public static copy (out: ray, a: ray): ray {
+ Vec3.copy(out.o, a.o);
+ Vec3.copy(out.d, a.d);
+
+ return out;
+ }
+
+ /**
+ * !#en
+ * create a ray from two points
+ * !#zh
+ * 用两个点创建一条射线。
+ * @method fromPoints
+ * @param {Ray} out Receive the operating ray.
+ * @param {Vec3} origin Origin of ray
+ * @param {Vec3} target A point on a ray.
+ * @return {Ray} out Receive the operating ray.
+ */
+ public static fromPoints (out: ray, origin: Vec3, target: Vec3): ray {
+ Vec3.copy(out.o, origin);
+ Vec3.normalize(out.d, Vec3.subtract(out.d, target, origin));
+ return out;
+ }
+
+ /**
+ * !#en
+ * Set the components of a ray to the given values
+ * !#zh
+ * 将给定射线的属性设置为给定的值。
+ * @method set
+ * @param {Ray} out Receive the operating ray.
+ * @param {number} ox The x part of the starting point.
+ * @param {number} oy The y part of the starting point.
+ * @param {number} oz The z part of the starting point.
+ * @param {number} dx X in the direction.
+ * @param {number} dy Y in the direction.
+ * @param {number} dz Z in the direction.
+ * @return {Ray} out Receive the operating ray.
+ */
+ public static set (out: ray, ox: number, oy: number, oz: number, dx: number, dy: number, dz: number): ray {
+ out.o.x = ox;
+ out.o.y = oy;
+ out.o.z = oz;
+ out.d.x = dx;
+ out.d.y = dy;
+ out.d.z = dz;
+
+ return out;
+ }
+
+ /**
+ * !#en
+ * Start point.
+ * !#zh
+ * 起点。
+ * @property {Vec3} o
+ */
+ public o: Vec3;
+
+ /**
+ * !#e
+ * Direction
+ * !#zh
+ * 方向。
+ * @property {Vec3} d
+ */
+ public d: Vec3;
+
+ private _type: number;
+
+ /**
+ * !#en Construct a ray.
+ * !#zh 构造一条射线。
+ * @constructor
+ * @param {number} ox The x part of the starting point.
+ * @param {number} oy The y part of the starting point.
+ * @param {number} oz The z part of the starting point.
+ * @param {number} dx X in the direction.
+ * @param {number} dy Y in the direction.
+ * @param {number} dz Z in the direction.
+ */
+ constructor (ox: number = 0, oy: number = 0, oz: number = 0,
+ dx: number = 0, dy: number = 0, dz: number = -1) {
+ this._type = enums.SHAPE_RAY;
+ this.o = new Vec3(ox, oy, oz);
+ this.d = new Vec3(dx, dy, dz);
+ }
+
+ /**
+ * !#en Compute hit.
+ * @method computeHit
+ * @param {IVec3Like} out
+ * @param {number} distance
+ */
+ public computeHit (out: IVec3Like, distance: number) {
+ Vec3.normalize(out, this.d)
+ Vec3.scaleAndAdd(out, this.o, out, distance);
+ }
+}
diff --git a/cocos2d/core/geom-utils/sphere.ts b/cocos2d/core/geom-utils/sphere.ts
new file mode 100644
index 00000000000..0981d545668
--- /dev/null
+++ b/cocos2d/core/geom-utils/sphere.ts
@@ -0,0 +1,236 @@
+/****************************************************************************
+ Copyright (c) 2019 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import { Mat4, Quat, Vec3 } from '../value-types';
+import enums from './enums';
+
+const _v3_tmp = new Vec3();
+
+/**
+ * !#en
+ * Sphere.
+ * !#zh
+ * 轴对齐球。
+ * @class geomUtils.Sphere
+ */
+export default class sphere {
+
+ /**
+ * !#en
+ * create a new sphere
+ * !#zh
+ * 创建一个新的 sphere 实例。
+ * @method create
+ * @param cx X coordinates of the shape relative to the origin.
+ * @param cy Y coordinates of the shape relative to the origin.
+ * @param cz Z coordinates of the shape relative to the origin.
+ * @param r Radius of sphere
+ * @return {Sphere} Returns a sphere.
+ */
+ public static create (cx: number, cy: number, cz: number, r: number): sphere {
+ return new sphere(cx, cy, cz, r);
+ }
+
+ /**
+ * !#en
+ * clone a new sphere
+ * !#zh
+ * 克隆一个新的 sphere 实例。
+ * @method clone
+ * @param {Sphere} p The target of cloning.
+ * @return {Sphere} The cloned instance.
+ */
+ public static clone (p: sphere): sphere {
+ return new sphere(p.center.x, p.center.y, p.center.z, p.radius);
+ }
+
+ /**
+ * !#en
+ * copy the values from one sphere to another
+ * !#zh
+ * 将从一个 sphere 的值复制到另一个 sphere。
+ * @method copy
+ * @param {Sphere} out Accept the sphere of operations.
+ * @param {Sphere} a Sphere being copied.
+ * @return {Sphere} out Accept the sphere of operations.
+ */
+ public static copy (out: sphere, p: sphere): sphere {
+ Vec3.copy(out.center, p.center);
+ out.radius = p.radius;
+
+ return out;
+ }
+
+ /**
+ * !#en
+ * create a new bounding sphere from two corner points
+ * !#zh
+ * 从两个点创建一个新的 sphere。
+ * @method fromPoints
+ * @param out - Accept the sphere of operations.
+ * @param minPos - The smallest point of sphere.
+ * @param maxPos - The maximum point of sphere.
+ * @returns {Sphere} out Accept the sphere of operations.
+ */
+ public static fromPoints (out: sphere, minPos: Vec3, maxPos: Vec3): sphere {
+ Vec3.multiplyScalar(out.center, Vec3.add(_v3_tmp, minPos, maxPos), 0.5);
+ out.radius = Vec3.subtract(_v3_tmp, maxPos, minPos).len() * 0.5;
+ return out;
+ }
+
+ /**
+ * !#en Set the components of a sphere to the given values
+ * !#zh 将球体的属性设置为给定的值。
+ * @method set
+ * @param {Sphere} out Accept the sphere of operations.
+ * @param cx X coordinates of the shape relative to the origin.
+ * @param cy Y coordinates of the shape relative to the origin.
+ * @param cz Z coordinates of the shape relative to the origin.
+ * @param {number} r Radius.
+ * @return {Sphere} out Accept the sphere of operations.
+ */
+ public static set (out: sphere, cx: number, cy: number, cz: number, r: number): sphere {
+ out.center.x = cx;
+ out.center.y = cy;
+ out.center.z = cz;
+ out.radius = r;
+
+ return out;
+ }
+
+ /**
+ * !#en
+ * The center of the local coordinate.
+ * !#zh
+ * 本地坐标的中心点。
+ * @property {Vec3} center
+ */
+ public center: Vec3;
+
+ /**
+ * !#zh
+ * 半径。
+ * @property {number} radius
+ */
+ public radius: number;
+
+ protected _type: number;
+
+ /**
+ * !#en
+ * Construct a sphere.
+ * !#zh
+ * 构造一个球。
+ * @constructor
+ * @param cx The x-coordinate of the sphere's world coordinates.
+ * @param cy The y-coordinate of the sphere's world coordinates.
+ * @param cz The z-coordinate of the sphere's world coordinates.
+ * @param {number} r Radius.
+ */
+ constructor (cx: number = 0, cy: number = 0, cz: number = 0, r: number = 1) {
+ this._type = enums.SHAPE_SPHERE;
+ this.center = new Vec3(cx, cy, cz);
+ this.radius = r;
+ }
+
+ /**
+ * !#en
+ * Clone.
+ * !#zh
+ * 获得克隆。
+ * @method clone
+ */
+ public clone () {
+ return sphere.clone(this);
+ }
+
+ /**
+ * !#en
+ * Copy sphere
+ * !#zh
+ * 拷贝对象。
+ * @method copy
+ * @param a Copy target.
+ */
+ public copy (a: sphere) {
+ return sphere.copy(this, a);
+ }
+
+ /**
+ * !#en
+ * Get the bounding points of this shape
+ * !#zh
+ * 获取此形状的边界点。
+ * @method getBoundary
+ * @param {Vec3} minPos
+ * @param {Vec3} maxPos
+ */
+ public getBoundary (minPos: Vec3, maxPos: Vec3) {
+ Vec3.set(minPos, this.center.x - this.radius, this.center.y - this.radius, this.center.z - this.radius);
+ Vec3.set(maxPos, this.center.x + this.radius, this.center.y + this.radius, this.center.z + this.radius);
+ }
+
+ /**
+ * !#en
+ * Transform this shape
+ * !#zh
+ * 将 out 根据这个 sphere 的数据进行变换。
+ * @method transform
+ * @param m The transformation matrix.
+ * @param pos The position part of the transformation.
+ * @param rot The rotating part of the transformation.
+ * @param scale The scaling part of the transformation.
+ * @param out The target of the transformation.
+ */
+ public transform (m: Mat4, pos: Vec3, rot: Quat, scale: Vec3, out: sphere) {
+ Vec3.transformMat4(out.center, this.center, m);
+ out.radius = this.radius * scale.maxAxis();
+ }
+
+ /**
+ * !#zh
+ * 将 out 根据这个 sphere 的数据进行变换。
+ * @translateAndRotate
+ * @param m The transformation matrix.
+ * @param rot The rotating part of the transformation.
+ * @param out The target of the transformation.
+ */
+ public translateAndRotate (m: Mat4, rot: Quat, out: sphere){
+ Vec3.transformMat4(out.center, this.center, m);
+ }
+
+ /**
+ * !#en
+ * Scale out based on the sphere data.
+ * !#zh
+ * 将 out 根据这个 sphere 的数据进行缩放。
+ * @method setScale
+ * @param scale Scale value
+ * @param out Scale target
+ */
+ public setScale (scale: Vec3, out: sphere) {
+ out.radius = this.radius * scale.maxAxis();
+ }
+}
diff --git a/cocos2d/core/geom-utils/triangle.ts b/cocos2d/core/geom-utils/triangle.ts
new file mode 100644
index 00000000000..d99bc3a9723
--- /dev/null
+++ b/cocos2d/core/geom-utils/triangle.ts
@@ -0,0 +1,167 @@
+/****************************************************************************
+ Copyright (c) 2019 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import Vec3 from '../value-types/vec3';
+import enums from './enums';
+
+/**
+ * Triangle
+ * @class geomUtils.Triangle
+ */
+export default class triangle {
+
+ /**
+ * create a new triangle
+ * @method create
+ * @param {number} ax
+ * @param {number} ay
+ * @param {number} az
+ * @param {number} bx
+ * @param {number} by
+ * @param {number} bz
+ * @param {number} cx
+ * @param {number} cy
+ * @param {number} cz
+ * @return {geomUtils.Triangle}
+ */
+ public static create (ax, ay, az, bx, by, bz, cx, cy, cz) {
+ return new triangle(ax, ay, az, bx, by, bz, cx, cy, cz);
+ }
+
+ /**
+ * clone a new triangle
+ * @method clone
+ * @param {geomUtils.Triangle} t the source plane
+ * @return {geomUtils.Triangle}
+ */
+ public static clone (t) {
+ return new triangle(
+ t.a.x, t.a.y, t.a.z,
+ t.b.x, t.b.y, t.b.z,
+ t.c.x, t.c.y, t.c.z
+ );
+ }
+
+ /**
+ * copy the values from one triangle to another
+ * @method copy
+ * @param {geomUtils.Triangle} out the receiving triangle
+ * @param {geomUtils.Triangle} t the source triangle
+ * @return {geomUtils.Triangle}
+ */
+ public static copy (out, t) {
+ Vec3.copy(out.a, t.a);
+ Vec3.copy(out.b, t.b);
+ Vec3.copy(out.c, t.c);
+
+ return out;
+ }
+
+ /**
+ * Create a triangle from three points
+ * @method fromPoints
+ * @param {geomUtils.Triangle} out the receiving triangle
+ * @param {Vec3} a
+ * @param {Vec3} b
+ * @param {Vec3} c
+ * @return {geomUtils.Triangle}
+ */
+ public static fromPoints (out, a, b, c) {
+ Vec3.copy(out.a, a);
+ Vec3.copy(out.b, b);
+ Vec3.copy(out.c, c);
+ return out;
+ }
+
+ /**
+ * Set the components of a triangle to the given values
+ *
+ * @method set
+ * @param {geomUtils.Triangle} out the receiving plane
+ * @param {number} ax X component of a
+ * @param {number} ay Y component of a
+ * @param {number} az Z component of a
+ * @param {number} bx X component of b
+ * @param {number} by Y component of b
+ * @param {number} bz Z component of b
+ * @param {number} cx X component of c
+ * @param {number} cy Y component of c
+ * @param {number} cz Z component of c
+ * @return {Plane}
+ */
+ public static set (out, ax, ay, az, bx, by, bz, cx, cy, cz) {
+ out.a.x = ax;
+ out.a.y = ay;
+ out.a.z = az;
+
+ out.b.x = bx;
+ out.b.y = by;
+ out.b.z = bz;
+
+ out.c.x = cx;
+ out.c.y = cy;
+ out.c.z = cz;
+
+ return out;
+ }
+
+ /**
+ * @property {Vec3} a
+ */
+ a: Vec3;
+ /**
+ * @property {Vec3} b
+ */
+ b: Vec3;
+ /**
+ * @property {Vec3} c
+ */
+ c: Vec3;
+
+ /**
+ * geometry type
+ */
+ _type: number;
+
+ /**
+ * create a new triangle
+ * @constructor
+ * @param {number} ax
+ * @param {number} ay
+ * @param {number} az
+ * @param {number} bx
+ * @param {number} by
+ * @param {number} bz
+ * @param {number} cx
+ * @param {number} cy
+ * @param {number} cz
+ */
+ constructor (ax: number, ay: number, az: number, bx: number, by: number, bz: number, cx: number, cy: number, cz: number) {
+ this.a = new Vec3(ax, ay, az);
+ this.b = new Vec3(bx, by, bz);
+ this.c = new Vec3(cx, cy, cz);
+ this._type = enums.SHAPE_TRIANGLE;;
+ }
+}
diff --git a/cocos2d/core/graphics/graphics.js b/cocos2d/core/graphics/graphics.js
index 39cfe49929a..606ed49510e 100644
--- a/cocos2d/core/graphics/graphics.js
+++ b/cocos2d/core/graphics/graphics.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -25,7 +25,7 @@
****************************************************************************/
const RenderComponent = require('../components/CCRenderComponent');
-const SpriteMaterial = require('../renderer/render-engine').SpriteMaterial;
+const Material = require('../assets/material/CCMaterial');
const Types = require('./types');
const LineCap = Types.LineCap;
@@ -33,7 +33,7 @@ const LineJoin = Types.LineJoin;
/**
* @class Graphics
- * @extends Component
+ * @extends RenderComponent
*/
let Graphics = cc.Class({
name: 'cc.Graphics',
@@ -44,11 +44,11 @@ let Graphics = cc.Class({
},
ctor () {
- this._impl = Graphics._assembler.createImpl(this);
+ this._impl = new Graphics._Impl(this);
},
properties: {
- _lineWidth: 1,
+ _lineWidth: 2,
_strokeColor: cc.Color.BLACK,
_lineJoin: LineJoin.MITER,
_lineCap: LineCap.BUTT,
@@ -171,39 +171,29 @@ let Graphics = cc.Class({
onRestore () {
if (!this._impl) {
- this._impl = Graphics._assembler.createImpl();
+ this._impl = new Graphics._Impl(this);
}
},
- onEnable () {
- this._super();
- this._activateMaterial();
- },
-
onDestroy () {
+ this.clear(true);
this._super();
- this._impl.clear(this, true);
this._impl = null;
},
- _activateMaterial () {
- // Ignore material in canvas
- if (cc.game.renderType === cc.game.RENDER_TYPE_CANVAS) {
- return;
- }
-
- this.node._renderFlag &= ~cc.RenderFlow.FLAG_RENDER;
- this.node._renderFlag |= cc.RenderFlow.FLAG_CUSTOM_IA_RENDER;
+ _getDefaultMaterial () {
+ return Material.getBuiltinMaterial('2d-graphics');
+ },
- if (this._material) {
- return;
+ _updateMaterial () {
+ let material = this._materials[0];
+ if (!material) return;
+ if (material.getDefine('CC_USE_MODEL') !== undefined) {
+ material.define('CC_USE_MODEL', true);
+ }
+ if (material.getDefine('CC_SUPPORT_standard_derivatives') !== undefined && cc.sys.glExtension('OES_standard_derivatives')) {
+ material.define('CC_SUPPORT_standard_derivatives', true);
}
-
- let material = new SpriteMaterial();
- material.useColor = false;
- material.useTexture = false;
- material.useModel = true;
- this._updateMaterial(material);
},
/**
@@ -352,7 +342,10 @@ let Graphics = cc.Class({
* @param {Boolean} [clean] Whether to clean the graphics inner cache.
*/
clear (clean) {
- this._impl.clear(this, clean);
+ this._impl.clear(clean);
+ if (this._assembler) {
+ this._assembler.clear(clean);
+ }
},
/**
@@ -370,7 +363,10 @@ let Graphics = cc.Class({
* @method stroke
*/
stroke () {
- Graphics._assembler.stroke(this);
+ if (!this._assembler) {
+ this._resetAssembler();
+ }
+ this._assembler.stroke(this);
},
/**
@@ -379,8 +375,13 @@ let Graphics = cc.Class({
* @method fill
*/
fill () {
- Graphics._assembler.fill(this);
+ if (!this._assembler) {
+ this._resetAssembler();
+ }
+ this._assembler.fill(this);
}
});
cc.Graphics = module.exports = Graphics;
+cc.Graphics.Types = Types;
+cc.Graphics.Helper = require('./helper');
diff --git a/cocos2d/core/graphics/helper.js b/cocos2d/core/graphics/helper.js
index d20b760500f..c5fb5e6bc3c 100644
--- a/cocos2d/core/graphics/helper.js
+++ b/cocos2d/core/graphics/helper.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/graphics/index.js b/cocos2d/core/graphics/index.js
index eb305138a05..0f1bfb5187b 100644
--- a/cocos2d/core/graphics/index.js
+++ b/cocos2d/core/graphics/index.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/graphics/types.js b/cocos2d/core/graphics/types.js
index 07efb1473ce..eef62c7760e 100644
--- a/cocos2d/core/graphics/types.js
+++ b/cocos2d/core/graphics/types.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/index.js b/cocos2d/core/index.js
index c52cb58def2..d7e79d11724 100644
--- a/cocos2d/core/index.js
+++ b/cocos2d/core/index.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -39,9 +39,10 @@ if (!CC_EDITOR || !Editor.isMainProcess) {
require('./collider/CCIntersection');
require('./physics');
require('./camera/CCCamera');
-
- require('./mesh');
- require('./3d');
+ require('./geom-utils');
}
+require('./mesh');
+require('./3d');
+
require('./base-ui/CCWidgetManager');
diff --git a/cocos2d/core/load-pipeline/CCLoader.js b/cocos2d/core/load-pipeline/CCLoader.js
deleted file mode 100644
index 50dfaca8c87..00000000000
--- a/cocos2d/core/load-pipeline/CCLoader.js
+++ /dev/null
@@ -1,1014 +0,0 @@
-/****************************************************************************
- Copyright (c) 2013-2016 Chukong Technologies Inc.
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-var js = require('../platform/js');
-var Pipeline = require('./pipeline');
-var LoadingItems = require('./loading-items');
-var AssetLoader = require('./asset-loader');
-var Downloader = require('./downloader');
-var Loader = require('./loader');
-var AssetTable = require('./asset-table');
-var callInNextTick = require('../platform/utils').callInNextTick;
-var AutoReleaseUtils = require('./auto-release-utils');
-// var pushToMap = require('../utils/misc').pushToMap;
-var ReleasedAssetChecker = CC_DEBUG && require('./released-asset-checker');
-
-var resources = new AssetTable();
-
-function getXMLHttpRequest () {
- return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('MSXML2.XMLHTTP');
-}
-
-var _info = {url: null, raw: false};
-
-// Convert a resources by finding its real url with uuid, otherwise we will use the uuid or raw url as its url
-// So we gurantee there will be url in result
-function getResWithUrl (res) {
- var id, result, isUuid;
- if (typeof res === 'object') {
- result = res;
- if (res.url) {
- return result;
- }
- else {
- id = res.uuid;
- }
- }
- else {
- result = {};
- id = res;
- }
- isUuid = result.type ? result.type === 'uuid' : cc.AssetLibrary._uuidInSettings(id);
- cc.AssetLibrary._getAssetInfoInRuntime(id, _info);
- result.url = !isUuid ? id : _info.url;
- if (_info.url && result.type === 'uuid' && _info.raw) {
- result.type = null;
- result.isRawAsset = true;
- }
- else if (!isUuid) {
- result.isRawAsset = true;
- }
- return result;
-}
-
-var _sharedResources = [];
-var _sharedList = [];
-
-/**
- * Loader for resource loading process. It's a singleton object.
- * @class loader
- * @extends Pipeline
- * @static
- */
-function CCLoader () {
- var assetLoader = new AssetLoader();
- var downloader = new Downloader();
- var loader = new Loader();
-
- Pipeline.call(this, [
- assetLoader,
- downloader,
- loader
- ]);
-
- /**
- * The asset loader in cc.loader's pipeline, it's by default the first pipe.
- * It's used to identify an asset's type, and determine how to download it.
- * @property assetLoader
- * @type {Object}
- */
- this.assetLoader = assetLoader;
-
- /**
- * The md5 pipe in cc.loader's pipeline, it could be absent if the project isn't build with md5 option.
- * It's used to modify the url to the real downloadable url with md5 suffix.
- * @property md5Pipe
- * @type {Object}
- */
- this.md5Pipe = null;
-
- /**
- * The downloader in cc.loader's pipeline, it's by default the second pipe.
- * It's used to download files with several handlers: pure text, image, script, audio, font, uuid.
- * You can add your own download function with addDownloadHandlers
- * @property downloader
- * @type {Object}
- */
- this.downloader = downloader;
-
- /**
- * The loader in cc.loader's pipeline, it's by default the third pipe.
- * It's used to parse downloaded content with several handlers: JSON, image, plist, fnt, uuid.
- * You can add your own download function with addLoadHandlers
- * @property loader
- * @type {Object}
- */
- this.loader = loader;
-
- this.onProgress = null;
-
- // assets to release automatically
- this._autoReleaseSetting = js.createMap(true);
-
- if (CC_DEBUG) {
- this._releasedAssetChecker_DEBUG = new ReleasedAssetChecker();
- }
-}
-js.extend(CCLoader, Pipeline);
-var proto = CCLoader.prototype;
-
-proto.init = function (director) {
- if (CC_DEBUG) {
- var self = this;
- director.on(cc.Director.EVENT_AFTER_UPDATE, function () {
- self._releasedAssetChecker_DEBUG.checkCouldRelease(self._cache);
- });
- }
-};
-
-/**
- * Gets a new XMLHttpRequest instance.
- * @method getXMLHttpRequest
- * @returns {XMLHttpRequest}
- */
-proto.getXMLHttpRequest = getXMLHttpRequest;
-
-/**
- * Add custom supported types handler or modify existing type handler for download process.
- * @example
- * cc.loader.addDownloadHandlers({
- * // This will match all url with `.scene` extension or all url with `scene` type
- * 'scene' : function (url, callback) {}
- * });
- * @method addDownloadHandlers
- * @param {Object} extMap Custom supported types with corresponded handler
- */
-proto.addDownloadHandlers = function (extMap) {
- this.downloader.addHandlers(extMap);
-};
-
-/**
- * Add custom supported types handler or modify existing type handler for load process.
- * @example
- * cc.loader.addLoadHandlers({
- * // This will match all url with `.scene` extension or all url with `scene` type
- * 'scene' : function (url, callback) {}
- * });
- * @method addLoadHandlers
- * @param {Object} extMap Custom supported types with corresponded handler
- */
-proto.addLoadHandlers = function (extMap) {
- this.loader.addHandlers(extMap);
-};
-
-/**
- * Load resources with a progression callback and a complete callback.
- * The progression callback is the same as Pipeline's {{#crossLink "LoadingItems/onProgress:method"}}onProgress{{/crossLink}}
- * The complete callback is almost the same as Pipeline's {{#crossLink "LoadingItems/onComplete:method"}}onComplete{{/crossLink}}
- * The only difference is when user pass a single url as resources, the complete callback will set its result directly as the second parameter.
- *
- * @example
- * cc.loader.load('a.png', function (err, tex) {
- * cc.log('Result should be a texture: ' + (tex instanceof cc.Texture2D));
- * });
- *
- * cc.loader.load('http://example.com/a.png', function (err, tex) {
- * cc.log('Should load a texture from external url: ' + (tex instanceof cc.Texture2D));
- * });
- *
- * cc.loader.load({url: 'http://example.com/getImageREST?file=a.png', type: 'png'}, function (err, tex) {
- * cc.log('Should load a texture from RESTful API by specify the type: ' + (tex instanceof cc.Texture2D));
- * });
- *
- * cc.loader.load(['a.png', 'b.json'], function (errors, results) {
- * if (errors) {
- * for (var i = 0; i < errors.length; i++) {
- * cc.log('Error url [' + errors[i] + ']: ' + results.getError(errors[i]));
- * }
- * }
- * var aTex = results.getContent('a.png');
- * var bJsonObj = results.getContent('b.json');
- * });
- *
- * @method load
- * @param {String|String[]|Object} resources - Url list in an array
- * @param {Function} [progressCallback] - Callback invoked when progression change
- * @param {Number} progressCallback.completedCount - The number of the items that are already completed
- * @param {Number} progressCallback.totalCount - The total number of the items
- * @param {Object} progressCallback.item - The latest item which flow out the pipeline
- * @param {Function} [completeCallback] - Callback invoked when all resources loaded
- * @typescript
- * load(resources: string|string[]|{uuid?: string, url?: string, type?: string}, completeCallback?: Function): void
- * load(resources: string|string[]|{uuid?: string, url?: string, type?: string}, progressCallback: (completedCount: number, totalCount: number, item: any) => void, completeCallback: Function|null): void
- */
-proto.load = function(resources, progressCallback, completeCallback) {
- if (CC_DEV && !resources) {
- return cc.error("[cc.loader.load] resources must be non-nil.");
- }
-
- if (completeCallback === undefined) {
- completeCallback = progressCallback;
- progressCallback = this.onProgress || null;
- }
-
- var self = this;
- var singleRes = false;
- var res;
- if (!(resources instanceof Array)) {
- if (resources) {
- singleRes = true;
- resources = [resources];
- } else {
- resources = [];
- }
- }
-
- _sharedResources.length = 0;
- for (var i = 0; i < resources.length; ++i) {
- var resource = resources[i];
- // Backward compatibility
- if (resource && resource.id) {
- cc.warnID(4920, resource.id);
- if (!resource.uuid && !resource.url) {
- resource.url = resource.id;
- }
- }
- res = getResWithUrl(resource);
- if (!res.url && !res.uuid)
- continue;
- var item = this._cache[res.url];
- _sharedResources.push(item || res);
- }
-
- var queue = LoadingItems.create(this, progressCallback, function (errors, items) {
- callInNextTick(function () {
- if (completeCallback) {
- if (singleRes) {
- let id = res.url;
- completeCallback.call(self, items.getError(id), items.getContent(id));
- }
- else {
- completeCallback.call(self, errors, items);
- }
- completeCallback = null;
- }
-
- if (CC_EDITOR) {
- for (let id in self._cache) {
- if (self._cache[id].complete) {
- self.removeItem(id);
- }
- }
- }
- items.destroy();
- });
- });
- LoadingItems.initQueueDeps(queue);
- queue.append(_sharedResources);
- _sharedResources.length = 0;
-};
-
-proto.flowInDeps = function (owner, urlList, callback) {
- _sharedList.length = 0;
- for (var i = 0; i < urlList.length; ++i) {
- var res = getResWithUrl(urlList[i]);
- if (!res.url && ! res.uuid)
- continue;
- var item = this._cache[res.url];
- if (item) {
- _sharedList.push(item);
- }
- else {
- _sharedList.push(res);
- }
- }
-
- var queue = LoadingItems.create(this, owner ? function (completedCount, totalCount, item) {
- if (this._ownerQueue && this._ownerQueue.onProgress) {
- this._ownerQueue._childOnProgress(item);
- }
- } : null, function (errors, items) {
- callback(errors, items);
- // Clear deps because it's already done
- // Each item will only flowInDeps once, so it's still safe here
- owner && owner.deps && (owner.deps.length = 0);
- items.destroy();
- });
- if (owner) {
- var ownerQueue = LoadingItems.getQueue(owner);
- // Set the root ownerQueue, if no ownerQueue defined in ownerQueue, it's the root
- queue._ownerQueue = ownerQueue._ownerQueue || ownerQueue;
- }
- var accepted = queue.append(_sharedList, owner);
- _sharedList.length = 0;
- return accepted;
-};
-
-proto._resources = resources;
-proto._getResUuid = function (url, type, quiet) {
- if (!url) {
- return null;
- }
- // Ignore parameter
- var index = url.indexOf('?');
- if (index !== -1)
- url = url.substr(0, index);
- var uuid = resources.getUuid(url, type);
- if ( !uuid ) {
- var extname = cc.path.extname(url);
- if (extname) {
- // strip extname
- url = url.slice(0, - extname.length);
- uuid = resources.getUuid(url, type);
- if (uuid && !quiet) {
- cc.warnID(4901, url, extname);
- }
- }
- }
- return uuid;
-};
-// Find the asset's reference id in loader, asset could be asset object, asset uuid or asset url
-proto._getReferenceKey = function (assetOrUrlOrUuid) {
- var key;
- if (typeof assetOrUrlOrUuid === 'object') {
- key = assetOrUrlOrUuid._uuid || null;
- }
- else if (typeof assetOrUrlOrUuid === 'string') {
- key = this._getResUuid(assetOrUrlOrUuid, null, true) || assetOrUrlOrUuid;
- }
- if (!key) {
- cc.warnID(4800, assetOrUrlOrUuid);
- return key;
- }
- cc.AssetLibrary._getAssetInfoInRuntime(key, _info);
- return this._cache[_info.url] ? _info.url : key;
-};
-
-proto._urlNotFound = function (url, type, completeCallback) {
- callInNextTick(function () {
- url = cc.url.normalize(url);
- var info = `${type ? js.getClassName(type) : 'Asset'} in "resources/${url}" does not exist.`;
- if (completeCallback) {
- completeCallback(new Error(info), []);
- }
- });
-};
-
-/**
- * @param {Function} [type]
- * @param {Function} [onProgress]
- * @param {Function} onComplete
- * @returns {Object} arguments
- * @returns {Function} arguments.type
- * @returns {Function} arguments.onProgress
- * @returns {Function} arguments.onComplete
- */
-proto._parseLoadResArgs = function (type, onProgress, onComplete) {
- if (onComplete === undefined) {
- var isValidType = js.isChildClassOf(type, cc.RawAsset);
- if (onProgress) {
- onComplete = onProgress;
- if (isValidType) {
- onProgress = this.onProgress || null;
- }
- }
- else if (onProgress === undefined && !isValidType) {
- onComplete = type;
- onProgress = this.onProgress || null;
- type = null;
- }
- if (onProgress !== undefined && !isValidType) {
- onProgress = type;
- type = null;
- }
- }
- return {
- type: type,
- onProgress: onProgress,
- onComplete: onComplete,
- };
-};
-
-/**
- * Load resources from the "resources" folder inside the "assets" folder of your project.
- *
- * Note: All asset URLs in Creator use forward slashes, URLs using backslashes will not work.
- *
- * @method loadRes
- * @param {String} url - Url of the target resource.
- * The url is relative to the "resources" folder, extensions must be omitted.
- * @param {Function} [type] - Only asset of type will be loaded if this argument is supplied.
- * @param {Function} [progressCallback] - Callback invoked when progression change.
- * @param {Number} progressCallback.completedCount - The number of the items that are already completed.
- * @param {Number} progressCallback.totalCount - The total number of the items.
- * @param {Object} progressCallback.item - The latest item which flow out the pipeline.
- * @param {Function} [completeCallback] - Callback invoked when the resource loaded.
- * @param {Error} completeCallback.error - The error info or null if loaded successfully.
- * @param {Object} completeCallback.resource - The loaded resource if it can be found otherwise returns null.
- *
- * @example
- *
- * // load the prefab (project/assets/resources/misc/character/cocos) from resources folder
- * cc.loader.loadRes('misc/character/cocos', function (err, prefab) {
- * if (err) {
- * cc.error(err.message || err);
- * return;
- * }
- * cc.log('Result should be a prefab: ' + (prefab instanceof cc.Prefab));
- * });
- *
- * // load the sprite frame of (project/assets/resources/imgs/cocos.png) from resources folder
- * cc.loader.loadRes('imgs/cocos', cc.SpriteFrame, function (err, spriteFrame) {
- * if (err) {
- * cc.error(err.message || err);
- * return;
- * }
- * cc.log('Result should be a sprite frame: ' + (spriteFrame instanceof cc.SpriteFrame));
- * });
- * @typescript
- * loadRes(url: string, type: typeof cc.Asset, progressCallback: (completedCount: number, totalCount: number, item: any) => void, completeCallback: ((error: Error, resource: any) => void)|null): void
- * loadRes(url: string, type: typeof cc.Asset, completeCallback: (error: Error, resource: any) => void): void
- * loadRes(url: string, type: typeof cc.Asset): void
- * loadRes(url: string, progressCallback: (completedCount: number, totalCount: number, item: any) => void, completeCallback: ((error: Error, resource: any) => void)|null): void
- * loadRes(url: string, completeCallback: (error: Error, resource: any) => void): void
- * loadRes(url: string): void
- */
-proto.loadRes = function (url, type, progressCallback, completeCallback) {
- var args = this._parseLoadResArgs(type, progressCallback, completeCallback);
- type = args.type;
- progressCallback = args.onProgress;
- completeCallback = args.onComplete;
- var self = this;
- var uuid = self._getResUuid(url, type);
- if (uuid) {
- this.load(
- {
- type: 'uuid',
- uuid: uuid
- },
- progressCallback,
- function (err, asset) {
- if (asset) {
- // should not release these assets, even if they are static referenced in the scene.
- self.setAutoReleaseRecursively(uuid, false);
- }
- if (completeCallback) {
- completeCallback(err, asset);
- }
- }
- );
- }
- else {
- self._urlNotFound(url, type, completeCallback);
- }
-};
-
-proto._loadResUuids = function (uuids, progressCallback, completeCallback, urls) {
- if (uuids.length > 0) {
- var self = this;
- var res = uuids.map(function (uuid) {
- return {
- type: 'uuid',
- uuid: uuid
- }
- });
- this.load(res, progressCallback, function (errors, items) {
- if (completeCallback) {
- var assetRes = [];
- var urlRes = urls && [];
- for (var i = 0; i < res.length; ++i) {
- var uuid = res[i].uuid;
- var id = this._getReferenceKey(uuid);
- var item = items.getContent(id);
- if (item) {
- // should not release these assets, even if they are static referenced in the scene.
- self.setAutoReleaseRecursively(uuid, false);
- assetRes.push(item);
- if (urlRes) {
- urlRes.push(urls[i]);
- }
- }
- }
- if (urls) {
- completeCallback(errors, assetRes, urlRes);
- }
- else {
- completeCallback(errors, assetRes);
- }
- }
- });
- }
- else {
- if (completeCallback) {
- callInNextTick(function () {
- if (urls) {
- completeCallback(null, [], []);
- }
- else {
- completeCallback(null, []);
- }
- });
- }
- }
-};
-
-/**
- * This method is like {{#crossLink "loader/loadRes:method"}}{{/crossLink}} except that it accepts array of url.
- *
- * @method loadResArray
- * @param {String[]} urls - Array of URLs of the target resource.
- * The url is relative to the "resources" folder, extensions must be omitted.
- * @param {Function} [type] - Only asset of type will be loaded if this argument is supplied.
- * @param {Function} [progressCallback] - Callback invoked when progression change.
- * @param {Number} progressCallback.completedCount - The number of the items that are already completed.
- * @param {Number} progressCallback.totalCount - The total number of the items.
- * @param {Object} progressCallback.item - The latest item which flow out the pipeline.
- * @param {Function} [completeCallback] - A callback which is called when all assets have been loaded, or an error occurs.
- * @param {Error} completeCallback.error - If one of the asset failed, the complete callback is immediately called
- * with the error. If all assets are loaded successfully, error will be null.
- * @param {Asset[]|Array} completeCallback.assets - An array of all loaded assets.
- * If nothing to load, assets will be an empty array.
- * @example
- *
- * // load the SpriteFrames from resources folder
- * var spriteFrames;
- * var urls = ['misc/characters/character_01', 'misc/weapons/weapons_01'];
- * cc.loader.loadResArray(urls, cc.SpriteFrame, function (err, assets) {
- * if (err) {
- * cc.error(err);
- * return;
- * }
- * spriteFrames = assets;
- * // ...
- * });
- * @typescript
- * loadResArray(url: string[], type: typeof cc.Asset, progressCallback: (completedCount: number, totalCount: number, item: any) => void, completeCallback: ((error: Error, resource: any[]) => void)|null): void
- * loadResArray(url: string[], type: typeof cc.Asset, completeCallback: (error: Error, resource: any[]) => void): void
- * loadResArray(url: string[], type: typeof cc.Asset): void
- * loadResArray(url: string[], progressCallback: (completedCount: number, totalCount: number, item: any) => void, completeCallback: ((error: Error, resource: any[]) => void)|null): void
- * loadResArray(url: string[], completeCallback: (error: Error, resource: any[]) => void): void
- * loadResArray(url: string[]): void
- */
-proto.loadResArray = function (urls, type, progressCallback, completeCallback) {
- var args = this._parseLoadResArgs(type, progressCallback, completeCallback);
- type = args.type;
- progressCallback = args.onProgress;
- completeCallback = args.onComplete;
-
- var uuids = [];
- for (var i = 0; i < urls.length; i++) {
- var url = urls[i];
- var uuid = this._getResUuid(url, type);
- if (uuid) {
- uuids.push(uuid);
- }
- else {
- this._urlNotFound(url, type, completeCallback);
- return;
- }
- }
- this._loadResUuids(uuids, progressCallback, completeCallback);
-};
-
-/**
- * Load all assets in a folder inside the "assets/resources" folder of your project.
- *
- * Note: All asset URLs in Creator use forward slashes, URLs using backslashes will not work.
- *
- * @method loadResDir
- * @param {String} url - Url of the target folder.
- * The url is relative to the "resources" folder, extensions must be omitted.
- * @param {Function} [type] - Only asset of type will be loaded if this argument is supplied.
- * @param {Function} [progressCallback] - Callback invoked when progression change.
- * @param {Number} progressCallback.completedCount - The number of the items that are already completed.
- * @param {Number} progressCallback.totalCount - The total number of the items.
- * @param {Object} progressCallback.item - The latest item which flow out the pipeline.
- * @param {Function} [completeCallback] - A callback which is called when all assets have been loaded, or an error occurs.
- * @param {Error} completeCallback.error - If one of the asset failed, the complete callback is immediately called
- * with the error. If all assets are loaded successfully, error will be null.
- * @param {Asset[]|Array} completeCallback.assets - An array of all loaded assets.
- * If nothing to load, assets will be an empty array.
- * @param {String[]} completeCallback.urls - An array that lists all the URLs of loaded assets.
- *
- * @example
- *
- * // load the texture (resources/imgs/cocos.png) and the corresponding sprite frame
- * cc.loader.loadResDir('imgs/cocos', function (err, assets) {
- * if (err) {
- * cc.error(err);
- * return;
- * }
- * var texture = assets[0];
- * var spriteFrame = assets[1];
- * });
- *
- * // load all textures in "resources/imgs/"
- * cc.loader.loadResDir('imgs', cc.Texture2D, function (err, textures) {
- * var texture1 = textures[0];
- * var texture2 = textures[1];
- * });
- *
- * // load all JSONs in "resources/data/"
- * cc.loader.loadResDir('data', function (err, objects, urls) {
- * var data = objects[0];
- * var url = urls[0];
- * });
- * @typescript
- * loadResDir(url: string, type: typeof cc.Asset, progressCallback: (completedCount: number, totalCount: number, item: any) => void, completeCallback: ((error: Error, resource: any[], urls: string[]) => void)|null): void
- * loadResDir(url: string, type: typeof cc.Asset, completeCallback: (error: Error, resource: any[], urls: string[]) => void): void
- * loadResDir(url: string, type: typeof cc.Asset): void
- * loadResDir(url: string, progressCallback: (completedCount: number, totalCount: number, item: any) => void, completeCallback: ((error: Error, resource: any[], urls: string[]) => void)|null): void
- * loadResDir(url: string, completeCallback: (error: Error, resource: any[], urls: string[]) => void): void
- * loadResDir(url: string): void
- */
-proto.loadResDir = function (url, type, progressCallback, completeCallback) {
- var args = this._parseLoadResArgs(type, progressCallback, completeCallback);
- type = args.type;
- progressCallback = args.onProgress;
- completeCallback = args.onComplete;
-
- var urls = [];
- var uuids = resources.getUuidArray(url, type, urls);
- this._loadResUuids(uuids, progressCallback, function (errors, assetRes, urlRes) {
- // The spriteFrame url in spriteAtlas will be removed after build project
- // To show users the exact structure in asset panel, we need to return the spriteFrame assets in spriteAtlas
- let assetResLength = assetRes.length;
- for (let i = 0; i < assetResLength; ++i) {
- if (assetRes[i] instanceof cc.SpriteAtlas) {
- let spriteFrames = assetRes[i].getSpriteFrames();
- for (let k in spriteFrames) {
- let sf = spriteFrames[k];
- assetRes.push(sf);
- if (urlRes) {
- urlRes.push(`${urlRes[i]}/${sf.name}`);
- }
- }
- }
- }
- completeCallback && completeCallback(errors, assetRes, urlRes);
- }, urls);
-};
-
-/**
- * Get resource data by id.
- * When you load resources with {{#crossLink "loader/load:method"}}{{/crossLink}} or {{#crossLink "loader/loadRes:method"}}{{/crossLink}},
- * the url will be the unique identity of the resource.
- * After loaded, you can acquire them by passing the url to this API.
- *
- * @method getRes
- * @param {String} url
- * @param {Function} [type] - Only asset of type will be returned if this argument is supplied.
- * @returns {*}
- */
-proto.getRes = function (url, type) {
- var item = this._cache[url];
- if (!item) {
- var uuid = this._getResUuid(url, type, true);
- if (uuid) {
- var ref = this._getReferenceKey(uuid);
- item = this._cache[ref];
- }
- else {
- return null;
- }
- }
- if (item && item.alias) {
- item = item.alias;
- }
- return (item && item.complete) ? item.content : null;
-};
-
-/**
- * Get total resources count in loader.
- * @returns {Number}
- */
-proto.getResCount = function () {
- return Object.keys(this._cache).length;
-};
-
-/**
- * !#en Get all resource dependencies of the requested asset in an array, including itself.
- * The owner parameter accept the following types: 1. The asset itself; 2. The resource url; 3. The asset's uuid.
- * The returned array stores the dependencies with their uuids, after retrieve dependencies,
- * you can release them, access dependent assets by passing the uuid to {{#crossLink "loader/getRes:method"}}{{/crossLink}}, or other stuffs you want.
- * For release all dependencies of an asset, please refer to {{#crossLink "loader/release:method"}}{{/crossLink}}
- * Here is some examples:
- * !#zh 获取一个指定资源的所有依赖资源,包含它自身,并保存在数组中返回。owner 参数接收以下几种类型:1. 资源 asset 对象;2. 资源目录下的 url;3. 资源的 uuid。
- * 返回的数组将仅保存依赖资源的 uuid,获取这些 uuid 后,你可以从 loader 释放这些资源;通过 {{#crossLink "loader/getRes:method"}}{{/crossLink}} 获取某个资源或者进行其他你需要的操作。
- * 想要释放一个资源及其依赖资源,可以参考 {{#crossLink "loader/release:method"}}{{/crossLink}}。下面是一些示例代码:
- *
- * @example
- * // Release all dependencies of a loaded prefab
- * var deps = cc.loader.getDependsRecursively(prefab);
- * cc.loader.release(deps);
- * // Retrieve all dependent textures
- * var deps = cc.loader.getDependsRecursively('prefabs/sample');
- * var textures = [];
- * for (var i = 0; i < deps.length; ++i) {
- * var item = cc.loader.getRes(deps[i]);
- * if (item instanceof cc.Texture2D) {
- * textures.push(item);
- * }
- * }
- *
- * @method getDependsRecursively
- * @param {Asset|RawAsset|String} owner - The owner asset or the resource url or the asset's uuid
- * @returns {Array}
- */
-proto.getDependsRecursively = function (owner) {
- if (owner) {
- var key = this._getReferenceKey(owner);
- var assets = AutoReleaseUtils.getDependsRecursively(key);
- assets.push(key);
- return assets;
- }
- else {
- return [];
- }
-};
-
-/**
- * !#en
- * Release the content of an asset or an array of assets by uuid.
- * Start from v1.3, this method will not only remove the cache of the asset in loader, but also clean up its content.
- * For example, if you release a texture, the texture asset and its gl texture data will be freed up.
- * In complexe project, you can use this function with {{#crossLink "loader/getDependsRecursively:method"}}{{/crossLink}} to free up memory in critical circumstances.
- * Notice, this method may cause the texture to be unusable, if there are still other nodes use the same texture, they may turn to black and report gl errors.
- * If you only want to remove the cache of an asset, please use {{#crossLink "pipeline/removeItem:method"}}{{/crossLink}}
- * !#zh
- * 通过 id(通常是资源 url)来释放一个资源或者一个资源数组。
- * 从 v1.3 开始,这个方法不仅会从 loader 中删除资源的缓存引用,还会清理它的资源内容。
- * 比如说,当你释放一个 texture 资源,这个 texture 和它的 gl 贴图数据都会被释放。
- * 在复杂项目中,我们建议你结合 {{#crossLink "loader/getDependsRecursively:method"}}{{/crossLink}} 来使用,便于在设备内存告急的情况下更快地释放不再需要的资源的内存。
- * 注意,这个函数可能会导致资源贴图或资源所依赖的贴图不可用,如果场景中存在节点仍然依赖同样的贴图,它们可能会变黑并报 GL 错误。
- * 如果你只想删除一个资源的缓存引用,请使用 {{#crossLink "pipeline/removeItem:method"}}{{/crossLink}}
- *
- * @example
- * // Release a texture which is no longer need
- * cc.loader.release(texture);
- * // Release all dependencies of a loaded prefab
- * var deps = cc.loader.getDependsRecursively('prefabs/sample');
- * cc.loader.release(deps);
- * // If there is no instance of this prefab in the scene, the prefab and its dependencies like textures, sprite frames, etc, will be freed up.
- * // If you have some other nodes share a texture in this prefab, you can skip it in two ways:
- * // 1. Forbid auto release a texture before release
- * cc.loader.setAutoRelease(texture2d, false);
- * // 2. Remove it from the dependencies array
- * var deps = cc.loader.getDependsRecursively('prefabs/sample');
- * var index = deps.indexOf(texture2d._uuid);
- * if (index !== -1)
- * deps.splice(index, 1);
- * cc.loader.release(deps);
- *
- * @method release
- * @param {Asset|RawAsset|String|Array} asset
- */
-proto.release = function (asset) {
- if (Array.isArray(asset)) {
- for (let i = 0; i < asset.length; i++) {
- var key = asset[i];
- this.release(key);
- }
- }
- else if (asset) {
- var id = this._getReferenceKey(asset);
- var item = this.getItem(id);
- if (item) {
- var removed = this.removeItem(id);
- asset = item.content;
- if (asset instanceof cc.Asset) {
- let nativeUrl = asset.nativeUrl;
- if (nativeUrl) {
- this.release(nativeUrl); // uncache loading item of native asset
- }
- asset.destroy();
- }
- if (CC_DEBUG && removed) {
- this._releasedAssetChecker_DEBUG.setReleased(item, id);
- }
- }
- }
-};
-
-/**
- * !#en Release the asset by its object. Refer to {{#crossLink "loader/release:method"}}{{/crossLink}} for detailed informations.
- * !#zh 通过资源对象自身来释放资源。详细信息请参考 {{#crossLink "loader/release:method"}}{{/crossLink}}
- *
- * @method releaseAsset
- * @param {Asset} asset
- */
-proto.releaseAsset = function (asset) {
- var uuid = asset._uuid;
- if (uuid) {
- this.release(uuid);
- }
-};
-
-/**
- * !#en Release the asset loaded by {{#crossLink "loader/loadRes:method"}}{{/crossLink}}. Refer to {{#crossLink "loader/release:method"}}{{/crossLink}} for detailed informations.
- * !#zh 释放通过 {{#crossLink "loader/loadRes:method"}}{{/crossLink}} 加载的资源。详细信息请参考 {{#crossLink "loader/release:method"}}{{/crossLink}}
- *
- * @method releaseRes
- * @param {String} url
- * @param {Function} [type] - Only asset of type will be released if this argument is supplied.
- */
-proto.releaseRes = function (url, type) {
- var uuid = this._getResUuid(url, type);
- if (uuid) {
- this.release(uuid);
- }
- else {
- cc.errorID(4914, url);
- }
-};
-
-/**
- * !#en Release the all assets loaded by {{#crossLink "loader/loadResDir:method"}}{{/crossLink}}. Refer to {{#crossLink "loader/release:method"}}{{/crossLink}} for detailed informations.
- * !#zh 释放通过 {{#crossLink "loader/loadResDir:method"}}{{/crossLink}} 加载的资源。详细信息请参考 {{#crossLink "loader/release:method"}}{{/crossLink}}
- *
- * @method releaseResDir
- * @param {String} url
- * @param {Function} [type] - Only asset of type will be released if this argument is supplied.
- */
-proto.releaseResDir = function (url, type) {
- var uuids = resources.getUuidArray(url, type);
- for (var i = 0; i < uuids.length; i++) {
- var uuid = uuids[i];
- this.release(uuid);
- }
-};
-
-/**
- * !#en Resource all assets. Refer to {{#crossLink "loader/release:method"}}{{/crossLink}} for detailed informations.
- * !#zh 释放所有资源。详细信息请参考 {{#crossLink "loader/release:method"}}{{/crossLink}}
- *
- * @method releaseAll
- */
-proto.releaseAll = function () {
- for (var id in this._cache) {
- this.release(id);
- }
-};
-
-// AUTO RELEASE
-
-// override
-proto.removeItem = function (key) {
- var removed = Pipeline.prototype.removeItem.call(this, key);
- delete this._autoReleaseSetting[key];
- return removed;
-};
-
-/**
- * !#en
- * Indicates whether to release the asset when loading a new scene.
- * By default, when loading a new scene, all assets in the previous scene will be released or preserved
- * according to whether the previous scene checked the "Auto Release Assets" option.
- * On the other hand, assets dynamically loaded by using `cc.loader.loadRes` or `cc.loader.loadResDir`
- * will not be affected by that option, remain not released by default.
- * Use this API to change the default behavior on a single asset, to force preserve or release specified asset when scene switching.
- *
- * See: {{#crossLink "loader/setAutoReleaseRecursively:method"}}cc.loader.setAutoReleaseRecursively{{/crossLink}}, {{#crossLink "loader/isAutoRelease:method"}}cc.loader.isAutoRelease{{/crossLink}}
- * !#zh
- * 设置当场景切换时是否自动释放资源。
- * 默认情况下,当加载新场景时,旧场景的资源根据旧场景是否勾选“Auto Release Assets”,将会被释放或者保留。
- * 而使用 `cc.loader.loadRes` 或 `cc.loader.loadResDir` 动态加载的资源,则不受场景设置的影响,默认不自动释放。
- * 使用这个 API 可以在单个资源上改变这个默认行为,强制在切换场景时保留或者释放指定资源。
- *
- * 参考:{{#crossLink "loader/setAutoReleaseRecursively:method"}}cc.loader.setAutoReleaseRecursively{{/crossLink}},{{#crossLink "loader/isAutoRelease:method"}}cc.loader.isAutoRelease{{/crossLink}}
- *
- * @example
- * // auto release the texture event if "Auto Release Assets" disabled in current scene
- * cc.loader.setAutoRelease(texture2d, true);
- * // don't release the texture even if "Auto Release Assets" enabled in current scene
- * cc.loader.setAutoRelease(texture2d, false);
- * // first parameter can be url
- * cc.loader.setAutoRelease(audioUrl, false);
- *
- * @method setAutoRelease
- * @param {Asset|String} assetOrUrlOrUuid - asset object or the raw asset's url or uuid
- * @param {Boolean} autoRelease - indicates whether should release automatically
- */
-proto.setAutoRelease = function (assetOrUrlOrUuid, autoRelease) {
- var key = this._getReferenceKey(assetOrUrlOrUuid);
- if (key) {
- this._autoReleaseSetting[key] = !!autoRelease;
- }
- else if (CC_DEV) {
- cc.warnID(4902);
- }
-};
-
-/**
- * !#en
- * Indicates whether to release the asset and its referenced other assets when loading a new scene.
- * By default, when loading a new scene, all assets in the previous scene will be released or preserved
- * according to whether the previous scene checked the "Auto Release Assets" option.
- * On the other hand, assets dynamically loaded by using `cc.loader.loadRes` or `cc.loader.loadResDir`
- * will not be affected by that option, remain not released by default.
- * Use this API to change the default behavior on the specified asset and its recursively referenced assets, to force preserve or release specified asset when scene switching.
- *
- * See: {{#crossLink "loader/setAutoRelease:method"}}cc.loader.setAutoRelease{{/crossLink}}, {{#crossLink "loader/isAutoRelease:method"}}cc.loader.isAutoRelease{{/crossLink}}
- * !#zh
- * 设置当场景切换时是否自动释放资源及资源引用的其它资源。
- * 默认情况下,当加载新场景时,旧场景的资源根据旧场景是否勾选“Auto Release Assets”,将会被释放或者保留。
- * 而使用 `cc.loader.loadRes` 或 `cc.loader.loadResDir` 动态加载的资源,则不受场景设置的影响,默认不自动释放。
- * 使用这个 API 可以在指定资源及资源递归引用到的所有资源上改变这个默认行为,强制在切换场景时保留或者释放指定资源。
- *
- * 参考:{{#crossLink "loader/setAutoRelease:method"}}cc.loader.setAutoRelease{{/crossLink}},{{#crossLink "loader/isAutoRelease:method"}}cc.loader.isAutoRelease{{/crossLink}}
- *
- * @example
- * // auto release the SpriteFrame and its Texture event if "Auto Release Assets" disabled in current scene
- * cc.loader.setAutoReleaseRecursively(spriteFrame, true);
- * // don't release the SpriteFrame and its Texture even if "Auto Release Assets" enabled in current scene
- * cc.loader.setAutoReleaseRecursively(spriteFrame, false);
- * // don't release the Prefab and all the referenced assets
- * cc.loader.setAutoReleaseRecursively(prefab, false);
- *
- * @method setAutoReleaseRecursively
- * @param {Asset|String} assetOrUrlOrUuid - asset object or the raw asset's url or uuid
- * @param {Boolean} autoRelease - indicates whether should release automatically
- */
-proto.setAutoReleaseRecursively = function (assetOrUrlOrUuid, autoRelease) {
- autoRelease = !!autoRelease;
- var key = this._getReferenceKey(assetOrUrlOrUuid);
- if (key) {
- this._autoReleaseSetting[key] = autoRelease;
-
- var depends = AutoReleaseUtils.getDependsRecursively(key);
- for (var i = 0; i < depends.length; i++) {
- var depend = depends[i];
- this._autoReleaseSetting[depend] = autoRelease;
- }
- }
- else if (CC_DEV) {
- cc.warnID(4902);
- }
-};
-
-
-/**
- * !#en
- * Returns whether the asset is configured as auto released, despite how "Auto Release Assets" property is set on scene asset.
- *
- * See: {{#crossLink "loader/setAutoRelease:method"}}cc.loader.setAutoRelease{{/crossLink}}, {{#crossLink "loader/setAutoReleaseRecursively:method"}}cc.loader.setAutoReleaseRecursively{{/crossLink}}
- *
- * !#zh
- * 返回指定的资源是否有被设置为自动释放,不论场景的“Auto Release Assets”如何设置。
- *
- * 参考:{{#crossLink "loader/setAutoRelease:method"}}cc.loader.setAutoRelease{{/crossLink}},{{#crossLink "loader/setAutoReleaseRecursively:method"}}cc.loader.setAutoReleaseRecursively{{/crossLink}}
- * @method isAutoRelease
- * @param {Asset|String} assetOrUrl - asset object or the raw asset's url
- * @returns {Boolean}
- */
-proto.isAutoRelease = function (assetOrUrl) {
- var key = this._getReferenceKey(assetOrUrl);
- if (key) {
- return !!this._autoReleaseSetting[key];
- }
- return false;
-};
-
-cc.loader = new CCLoader();
-
-if (CC_EDITOR) {
- cc.loader.refreshUrl = function (uuid, oldUrl, newUrl) {
- var item = this._cache[uuid];
- if (item) {
- item.url = newUrl;
- }
-
- item = this._cache[oldUrl];
- if (item) {
- item.id = newUrl;
- item.url = newUrl;
- this._cache[newUrl] = item;
- delete this._cache[oldUrl];
- }
- };
-}
-
-module.exports = cc.loader;
diff --git a/cocos2d/core/load-pipeline/asset-loader.js b/cocos2d/core/load-pipeline/asset-loader.js
deleted file mode 100644
index 6c9d74c9273..00000000000
--- a/cocos2d/core/load-pipeline/asset-loader.js
+++ /dev/null
@@ -1,89 +0,0 @@
-/****************************************************************************
- Copyright (c) 2016 Chukong Technologies Inc.
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-require('../utils/CCPath');
-const debug = require('../CCDebug');
-const Pipeline = require('./pipeline');
-const LoadingItems = require('./loading-items');
-
-var ID = 'AssetLoader';
-
-var AssetLoader = function (extMap) {
- this.id = ID;
- this.async = true;
- this.pipeline = null;
-};
-AssetLoader.ID = ID;
-
-var reusedArray = [];
-AssetLoader.prototype.handle = function (item, callback) {
- var uuid = item.uuid;
- if (!uuid) {
- return item.content || null;
- }
-
- var self = this;
- cc.AssetLibrary.queryAssetInfo(uuid, function (error, url, isRawAsset) {
- if (error) {
- callback(error);
- }
- else {
- item.url = item.rawUrl = url;
- item.isRawAsset = isRawAsset;
- if (isRawAsset) {
- var ext = cc.path.extname(url).toLowerCase();
- if (!ext) {
- callback(new Error(debug.getError(4931, uuid, url)));
- return;
- }
- ext = ext.substr(1);
- var queue = LoadingItems.getQueue(item);
- reusedArray[0] = {
- queueId: item.queueId,
- id: url,
- url: url,
- type: ext,
- error: null,
- alias: item,
- complete: true
- };
- if (CC_EDITOR) {
- self.pipeline._cache[url] = reusedArray[0];
- }
- queue.append(reusedArray);
- // Dispatch to other raw type downloader
- item.type = ext;
- callback(null, item.content);
- }
- else {
- item.type = 'uuid';
- callback(null, item.content);
- }
- }
- });
-};
-
-Pipeline.AssetLoader = module.exports = AssetLoader;
\ No newline at end of file
diff --git a/cocos2d/core/load-pipeline/asset-table.js b/cocos2d/core/load-pipeline/asset-table.js
deleted file mode 100644
index 94a9ba0526d..00000000000
--- a/cocos2d/core/load-pipeline/asset-table.js
+++ /dev/null
@@ -1,199 +0,0 @@
-/****************************************************************************
- Copyright (c) 2013-2016 Chukong Technologies Inc.
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-var pushToMap = require('../utils/misc').pushToMap;
-var js = require('../platform/js');
-
-function Entry (uuid, type) {
- this.uuid = uuid;
- this.type = type;
-}
-
-/*
- * !#en AssetTable is used to find asset's uuid by url.
- * !#zh AssetTable 用于查找资源的 uuid 和 url。
- * @class AssetTable
- *
- */
-
-function AssetTable () {
- this._pathToUuid = js.createMap(true);
-}
-
-function isMatchByWord (path, test) {
- if (path.length > test.length) {
- var nextAscii = path.charCodeAt(test.length);
- return (nextAscii === 46 || nextAscii === 47); // '.' or '/'
- }
- return true;
-}
-
-var proto = AssetTable.prototype;
-
-proto.getUuid = function (path, type) {
- path = cc.url.normalize(path);
- var item = this._pathToUuid[path];
- if (item) {
- if (Array.isArray(item)) {
- if (type) {
- for (var i = 0; i < item.length; i++) {
- var entry = item[i];
- if (js.isChildClassOf(entry.type, type)) {
- return entry.uuid;
- }
- }
- // not found
- if (CC_DEBUG && js.isChildClassOf(type, cc.SpriteFrame)) {
- for (let i = 0; i < item.length; i++) {
- let entry = item[i];
- if (js.isChildClassOf(entry.type, cc.SpriteAtlas)) {
- // not support sprite frame in atlas
- cc.errorID(4932, path);
- break;
- }
- }
- }
- }
- else {
- return item[0].uuid;
- }
- }
- else if (!type || js.isChildClassOf(item.type, type)) {
- return item.uuid;
- }
- else if (CC_DEBUG && js.isChildClassOf(type, cc.SpriteFrame) && js.isChildClassOf(item.type, cc.SpriteAtlas)) {
- // not support sprite frame in atlas
- cc.errorID(4932, path);
- }
- }
- return '';
-};
-
-proto.getUuidArray = function (path, type, out_urls) {
- path = cc.url.normalize(path);
- if (path[path.length - 1] === '/') {
- path = path.slice(0, -1);
- }
- var path2uuid = this._pathToUuid;
- var uuids = [];
- var isChildClassOf = js.isChildClassOf;
- var _foundAtlasUrl;
- for (var p in path2uuid) {
- if ((p.startsWith(path) && isMatchByWord(p, path)) || !path) {
- var item = path2uuid[p];
- if (Array.isArray(item)) {
- for (var i = 0; i < item.length; i++) {
- var entry = item[i];
- if (!type || isChildClassOf(entry.type, type)) {
- uuids.push(entry.uuid);
- if (out_urls) {
- out_urls.push(p);
- }
- }
- else if (CC_DEBUG && entry.type === cc.SpriteAtlas) {
- _foundAtlasUrl = p;
- }
- }
- }
- else {
- if (!type || isChildClassOf(item.type, type)) {
- uuids.push(item.uuid);
- if (out_urls) {
- out_urls.push(p);
- }
- }
- else if (CC_DEBUG && item.type === cc.SpriteAtlas) {
- _foundAtlasUrl = p;
- }
- }
- }
- }
- if (CC_DEBUG && uuids.length === 0 && _foundAtlasUrl && js.isChildClassOf(type, cc.SpriteFrame)) {
- // not support sprite frame in atlas
- cc.errorID(4932, _foundAtlasUrl);
- }
- return uuids;
-};
-
-// /**
-// * !#en Returns all asset paths in the table.
-// * !#zh 返回表中的所有资源路径。
-// * @method getAllPaths
-// * @return {string[]}
-// */
-// proto.getAllPaths = function () {
-// return Object.keys(this._pathToUuid);
-// };
-
-/**
- * !#en TODO
- * !#zh 以路径为 key,uuid 为值添加到表中。
- * @method add
- * @param {String} path - the path to load, should NOT include filename extensions.
- * @param {String} uuid
- * @param {Function} type
- * @param {Boolean} isMainAsset
- * @private
- */
-proto.add = function (path, uuid, type, isMainAsset) {
- // remove extname
- // (can not use path.slice because length of extname maybe 0)
- path = path.substring(0, path.length - cc.path.extname(path).length);
- var newEntry = new Entry(uuid, type);
- pushToMap(this._pathToUuid, path, newEntry, isMainAsset);
-};
-
-proto._getInfo_DEBUG = CC_DEBUG && function (uuid, out_info) {
- var path2uuid = this._pathToUuid;
- var paths = Object.keys(path2uuid);
- for (var p = 0; p < paths.length; ++p) {
- var path = paths[p];
- var item = path2uuid[path];
- if (Array.isArray(item)) {
- for (var i = 0; i < item.length; i++) {
- var entry = item[i];
- if (entry.uuid === uuid) {
- out_info.path = path;
- out_info.type = entry.type;
- return true;
- }
- }
- }
- else if (item.uuid === uuid) {
- out_info.path = path;
- out_info.type = item.type;
- return true;
- }
- }
- return false;
-};
-
-proto.reset = function () {
- this._pathToUuid = js.createMap(true);
-};
-
-
-module.exports = AssetTable;
diff --git a/cocos2d/core/load-pipeline/auto-release-utils.js b/cocos2d/core/load-pipeline/auto-release-utils.js
deleted file mode 100644
index 095cd086511..00000000000
--- a/cocos2d/core/load-pipeline/auto-release-utils.js
+++ /dev/null
@@ -1,140 +0,0 @@
-/****************************************************************************
- Copyright (c) 2016 Chukong Technologies Inc.
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-var js = require('../platform/js');
-
-function parseDepends (key, parsed) {
- var item = cc.loader.getItem(key);
- if (item) {
- var depends = item.dependKeys;
- if (depends) {
- for (var i = 0; i < depends.length; i++) {
- var depend = depends[i];
- if ( !parsed[depend] ) {
- parsed[depend] = true;
- parseDepends(depend, parsed);
- }
- }
- }
- }
-}
-
-function visitAsset (asset, excludeMap) {
- // Skip assets generated programmatically or by user (e.g. label texture)
- if (!asset._uuid) {
- return;
- }
- var key = cc.loader._getReferenceKey(asset);
- if ( !excludeMap[key] ) {
- excludeMap[key] = true;
- parseDepends(key, excludeMap);
- }
-}
-
-function visitComponent (comp, excludeMap) {
- var props = Object.getOwnPropertyNames(comp);
- for (var i = 0; i < props.length; i++) {
- var value = comp[props[i]];
- if (typeof value === 'object' && value) {
- if (Array.isArray(value)) {
- for (let j = 0; j < value.length; j++) {
- let val = value[j];
- if (val instanceof cc.RawAsset) {
- visitAsset(val, excludeMap);
- }
- }
- }
- else if (!value.constructor || value.constructor === Object) {
- let keys = Object.getOwnPropertyNames(value);
- for (let j = 0; j < keys.length; j++) {
- let val = value[keys[j]];
- if (val instanceof cc.RawAsset) {
- visitAsset(val, excludeMap);
- }
- }
- }
- else if (value instanceof cc.RawAsset) {
- visitAsset(value, excludeMap);
- }
- }
- }
-}
-
-function visitNode (node, excludeMap) {
- for (let i = 0; i < node._components.length; i++) {
- visitComponent(node._components[i], excludeMap);
- }
- for (let i = 0; i < node._children.length; i++) {
- visitNode(node._children[i], excludeMap);
- }
-}
-
-module.exports = {
- // do auto release
- autoRelease: function (oldSceneAssets, nextSceneAssets, persistNodes) {
- var releaseSettings = cc.loader._autoReleaseSetting;
- var excludeMap = js.createMap();
-
- // collect next scene assets
- if (nextSceneAssets) {
- for (let i = 0; i < nextSceneAssets.length; i++) {
- excludeMap[nextSceneAssets[i]] = true;
- }
- }
-
- // collect assets used by persist nodes
- for (let i = 0; i < persistNodes.length; i++) {
- visitNode(persistNodes[i], excludeMap)
- }
-
- // remove ununsed scene assets
- if (oldSceneAssets) {
- for (let i = 0; i < oldSceneAssets.length; i++) {
- let key = oldSceneAssets[i];
- if (releaseSettings[key] !== false && !excludeMap[key]) {
- cc.loader.release(key);
- }
- }
- }
-
- // remove auto release assets
- // (releasing asset will change _autoReleaseSetting, so don't use for-in)
- var keys = Object.keys(releaseSettings);
- for (let i = 0; i < keys.length; i++) {
- let key = keys[i];
- if (releaseSettings[key] === true && !excludeMap[key]) {
- cc.loader.release(key);
- }
- }
- },
-
- // get dependencies not including self
- getDependsRecursively: function (key) {
- var depends = {};
- parseDepends(key, depends);
- return Object.keys(depends);
- }
-};
diff --git a/cocos2d/core/load-pipeline/downloader.js b/cocos2d/core/load-pipeline/downloader.js
deleted file mode 100644
index b58cfe862e8..00000000000
--- a/cocos2d/core/load-pipeline/downloader.js
+++ /dev/null
@@ -1,315 +0,0 @@
-/****************************************************************************
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-const js = require('../platform/js');
-const debug = require('../CCDebug');
-require('../utils/CCPath');
-const Pipeline = require('./pipeline');
-const PackDownloader = require('./pack-downloader');
-
-let downloadBinary = require('./binary-downloader');
-let downloadText = require('./text-downloader');
-let urlAppendTimestamp = require('./utils').urlAppendTimestamp;
-
-var downloadAudio;
-if (!CC_EDITOR || !Editor.isMainProcess) {
- downloadAudio = require('./audio-downloader');
-}
-else {
- downloadAudio = null;
-}
-
-function skip () {
- return null;
-}
-
-function downloadScript (item, callback, isAsync) {
- var url = item.url,
- d = document,
- s = document.createElement('script');
- s.async = isAsync;
- s.src = urlAppendTimestamp(url);
- function loadHandler () {
- s.parentNode.removeChild(s);
- s.removeEventListener('load', loadHandler, false);
- s.removeEventListener('error', errorHandler, false);
- callback(null, url);
- }
- function errorHandler() {
- s.parentNode.removeChild(s);
- s.removeEventListener('load', loadHandler, false);
- s.removeEventListener('error', errorHandler, false);
- callback(new Error(debug.getError(4928, url)));
- }
- s.addEventListener('load', loadHandler, false);
- s.addEventListener('error', errorHandler, false);
- d.body.appendChild(s);
-}
-
-function downloadWebp (item, callback, isCrossOrigin, img) {
- if (!cc.sys.capabilities.webp) {
- return new Error(debug.getError(4929, item.url));
- }
- return downloadImage(item, callback, isCrossOrigin, img);
-}
-
-function downloadImage (item, callback, isCrossOrigin, img) {
- if (isCrossOrigin === undefined) {
- isCrossOrigin = true;
- }
-
- var url = urlAppendTimestamp(item.url);
- img = img || new Image();
- if (isCrossOrigin && window.location.protocol !== 'file:') {
- img.crossOrigin = 'anonymous';
- }
- else {
- img.crossOrigin = null;
- }
-
- if (img.complete && img.naturalWidth > 0 && img.src === url) {
- return img;
- }
- else {
- function loadCallback () {
- img.removeEventListener('load', loadCallback);
- img.removeEventListener('error', errorCallback);
-
- img.id = item.id;
- callback(null, img);
- }
- function errorCallback () {
- img.removeEventListener('load', loadCallback);
- img.removeEventListener('error', errorCallback);
-
- // Retry without crossOrigin mark if crossOrigin loading fails
- // Do not retry if protocol is https, even if the image is loaded, cross origin image isn't renderable.
- if (window.location.protocol !== 'https:' && img.crossOrigin && img.crossOrigin.toLowerCase() === 'anonymous') {
- downloadImage(item, callback, false, img);
- }
- else {
- callback(new Error(debug.getError(4930, url)));
- }
- }
-
- img.addEventListener('load', loadCallback);
- img.addEventListener('error', errorCallback);
- img.src = url;
- }
-}
-
-function downloadUuid (item, callback) {
- var result = PackDownloader.load(item, callback);
- if (result === undefined) {
- return this.extMap['json'](item, callback);
- }
- return result || undefined;
-}
-
-
-var defaultMap = {
- // JS
- 'js' : downloadScript,
-
- // Images
- 'png' : downloadImage,
- 'jpg' : downloadImage,
- 'bmp' : downloadImage,
- 'jpeg' : downloadImage,
- 'gif' : downloadImage,
- 'ico' : downloadImage,
- 'tiff' : downloadImage,
- 'webp' : downloadWebp,
- 'image' : downloadImage,
- 'pvr': downloadBinary,
- 'etc': downloadBinary,
-
- // Audio
- 'mp3' : downloadAudio,
- 'ogg' : downloadAudio,
- 'wav' : downloadAudio,
- 'm4a' : downloadAudio,
-
- // Txt
- 'txt' : downloadText,
- 'xml' : downloadText,
- 'vsh' : downloadText,
- 'fsh' : downloadText,
- 'atlas' : downloadText,
-
- 'tmx' : downloadText,
- 'tsx' : downloadText,
-
- 'json' : downloadText,
- 'ExportJson' : downloadText,
- 'plist' : downloadText,
-
- 'fnt' : downloadText,
-
- // Font
- 'font' : skip,
- 'eot' : skip,
- 'ttf' : skip,
- 'woff' : skip,
- 'svg' : skip,
- 'ttc' : skip,
-
- // Deserializer
- 'uuid' : downloadUuid,
-
- // Binary
- 'binary' : downloadBinary,
- 'bin': downloadBinary,
-
- 'default' : downloadText
-};
-
-var ID = 'Downloader';
-
-/**
- * The downloader pipe, it can download several types of files:
- * 1. Text
- * 2. Image
- * 3. Script
- * 4. Audio
- * 5. Assets
- * All unknown type will be downloaded as plain text.
- * You can pass custom supported types in the constructor.
- * @class Pipeline.Downloader
- */
-/**
- * Constructor of Downloader, you can pass custom supported types.
- *
- * @method constructor
- * @param {Object} extMap Custom supported types with corresponded handler
- * @example
- * var downloader = new Downloader({
- * // This will match all url with `.scene` extension or all url with `scene` type
- * 'scene' : function (url, callback) {}
- * });
- */
-var Downloader = function (extMap) {
- this.id = ID;
- this.async = true;
- this.pipeline = null;
- this._curConcurrent = 0;
- this._loadQueue = [];
-
- this._subpackages = {};
-
- this.extMap = js.mixin(extMap, defaultMap);
-};
-Downloader.ID = ID;
-Downloader.PackDownloader = PackDownloader;
-
-/**
- * Add custom supported types handler or modify existing type handler.
- * @method addHandlers
- * @param {Object} extMap Custom supported types with corresponded handler
- */
-Downloader.prototype.addHandlers = function (extMap) {
- js.mixin(this.extMap, extMap);
-};
-
-Downloader.prototype._handleLoadQueue = function () {
- while (this._curConcurrent < cc.macro.DOWNLOAD_MAX_CONCURRENT) {
- var nextOne = this._loadQueue.shift();
- if (!nextOne) {
- break;
- }
- var syncRet = this.handle(nextOne.item, nextOne.callback);
- if (syncRet !== undefined) {
- if (syncRet instanceof Error) {
- nextOne.callback(syncRet);
- }
- else {
- nextOne.callback(null, syncRet);
- }
- }
- }
-};
-
-Downloader.prototype.handle = function (item, callback) {
- var self = this;
- var downloadFunc = this.extMap[item.type] || this.extMap['default'];
- var syncRet = undefined;
- if (this._curConcurrent < cc.macro.DOWNLOAD_MAX_CONCURRENT) {
- this._curConcurrent++;
- syncRet = downloadFunc.call(this, item, function (err, result) {
- self._curConcurrent = Math.max(0, self._curConcurrent - 1);
- self._handleLoadQueue();
- callback && callback(err, result);
- });
- if (syncRet !== undefined) {
- this._curConcurrent = Math.max(0, this._curConcurrent - 1);
- this._handleLoadQueue();
- return syncRet;
- }
- }
- else if (item.ignoreMaxConcurrency) {
- syncRet = downloadFunc.call(this, item, callback);
- if (syncRet !== undefined) {
- return syncRet;
- }
- }
- else {
- this._loadQueue.push({
- item: item,
- callback: callback
- });
- }
-};
-
-/**
- * !#en
- * Load subpackage with name.
- * !#zh
- * 通过子包名加载子包代码。
- * @method loadSubpackage
- * @param {String} name - Subpackage name
- * @param {Function} [completeCallback] - Callback invoked when subpackage loaded
- * @param {Error} completeCallback.error - error information
- */
-Downloader.prototype.loadSubpackage = function (name, completeCallback) {
- let pac = this._subpackages[name];
- if (pac) {
- if (pac.loaded) {
- if (completeCallback) completeCallback();
- }
- else {
- downloadScript({url: pac.path}, function (err) {
- if (!err) {
- pac.loaded = true;
- }
- if (completeCallback) completeCallback(err);
- });
- }
- }
- else if (completeCallback) {
- completeCallback(new Error(`Can't find subpackage ${name}`));
- }
-};
-
-Pipeline.Downloader = module.exports = Downloader;
diff --git a/cocos2d/core/load-pipeline/loader.js b/cocos2d/core/load-pipeline/loader.js
deleted file mode 100644
index a972d976543..00000000000
--- a/cocos2d/core/load-pipeline/loader.js
+++ /dev/null
@@ -1,249 +0,0 @@
-/****************************************************************************
- Copyright (c) 2013-2016 Chukong Technologies Inc.
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-const js = require('../platform/js');
-const plistParser = require('../platform/CCSAXParser').plistParser;
-const Pipeline = require('./pipeline');
-const Texture2D = require('../assets/CCTexture2D');
-const loadUuid = require('./uuid-loader');
-const fontLoader = require('./font-loader');
-
-function loadNothing () {
- return null;
-}
-
-function loadJSON (item) {
- if (typeof item.content !== 'string') {
- return new Error('JSON Loader: Input item doesn\'t contain string content');
- }
-
- try {
- var result = JSON.parse(item.content);
- return result;
- }
- catch (e) {
- return new Error('JSON Loader: Parse json [' + item.id + '] failed : ' + e);
- }
-}
-
-function loadImage (item) {
- var loadByDeserializedAsset = (item._owner instanceof cc.Asset);
- if (loadByDeserializedAsset) {
- // already has cc.Asset
- return null;
- }
-
- var image = item.content;
- if (!CC_WECHATGAME && !CC_QQPLAY && !(image instanceof Image)) {
- return new Error('Image Loader: Input item doesn\'t contain Image content');
- }
-
- // load cc.Texture2D
- var rawUrl = item.rawUrl;
- var tex = item.texture || new Texture2D();
- tex._uuid = item.uuid;
- tex.url = rawUrl;
- tex._setRawAsset(rawUrl, false);
- tex._nativeAsset = image;
- return tex;
-}
-
-// If audio is loaded by url directly, than this loader will wrap it into a new cc.AudioClip object.
-// If audio is loaded by deserialized AudioClip, than this loader will be skipped.
-function loadAudioAsAsset (item, callback) {
- var loadByDeserializedAsset = (item._owner instanceof cc.Asset);
- if (loadByDeserializedAsset) {
- // already has cc.Asset
- return null;
- }
-
- var audioClip = new cc.AudioClip();
- audioClip._setRawAsset(item.rawUrl, false);
- audioClip._nativeAsset = item.content;
- return audioClip;
-}
-
-function loadPlist (item) {
- if (typeof item.content !== 'string') {
- return new Error('Plist Loader: Input item doesn\'t contain string content');
- }
- var result = plistParser.parse(item.content);
- if (result) {
- return result;
- }
- else {
- return new Error('Plist Loader: Parse [' + item.id + '] failed');
- }
-}
-
-function loadBinary (item) {
- // Invoke custom handle
- if (item.load) {
- return item.load(item.content);
- }
- else {
- return null;
- }
-}
-
-//===============//
-// PVR constants //
-//===============//
-// https://github.com/toji/texture-tester/blob/master/js/webgl-texture-util.js#L424
-const PVR_HEADER_LENGTH = 13; // The header length in 32 bit ints.
-const PVR_MAGIC = 0x03525650; //0x50565203;
-
-// Offsets into the header array.
-const PVR_HEADER_MAGIC = 0;
-const PVR_HEADER_FORMAT = 2;
-const PVR_HEADER_HEIGHT = 6;
-const PVR_HEADER_WIDTH = 7;
-const PVR_HEADER_MIPMAPCOUNT = 11;
-const PVR_HEADER_METADATA = 12;
-
-function loadCompressedTex (item) {
- // Get a view of the arrayBuffer that represents the DDS header.
- let header = new Int32Array(item.content.buffer, 0, PVR_HEADER_LENGTH);
-
- // Do some sanity checks to make sure this is a valid DDS file.
- if(header[PVR_HEADER_MAGIC] != PVR_MAGIC) {
- return new Error("Invalid magic number in PVR header");
- }
-
- // Gather other basic metrics and a view of the raw the DXT data.
- let width = header[PVR_HEADER_WIDTH];
- let height = header[PVR_HEADER_HEIGHT];
- let levels = header[PVR_HEADER_MIPMAPCOUNT];
- let dataOffset = header[PVR_HEADER_METADATA] + 52;
- let pvrtcData = new Uint8Array(item.content.buffer, dataOffset);
-
- let pvrAsset = {
- _data: pvrtcData,
- _compressed: true,
-
- width: width,
- height: height,
- };
-
- return pvrAsset;
-}
-
-var defaultMap = {
- // Images
- 'png' : loadImage,
- 'jpg' : loadImage,
- 'bmp' : loadImage,
- 'jpeg' : loadImage,
- 'gif' : loadImage,
- 'ico' : loadImage,
- 'tiff' : loadImage,
- 'webp' : loadImage,
- 'image' : loadImage,
- 'pvr' : loadCompressedTex,
- 'etc' : loadCompressedTex,
-
- // Audio
- 'mp3' : loadAudioAsAsset,
- 'ogg' : loadAudioAsAsset,
- 'wav' : loadAudioAsAsset,
- 'm4a' : loadAudioAsAsset,
-
- // json
- 'json' : loadJSON,
- 'ExportJson' : loadJSON,
-
- // plist
- 'plist' : loadPlist,
-
- // asset
- 'uuid' : loadUuid,
- 'prefab' : loadUuid,
- 'fire' : loadUuid,
- 'scene' : loadUuid,
-
- // binary
- 'binary' : loadBinary,
-
- // Font
- 'font' : fontLoader.loadFont,
- 'eot' : fontLoader.loadFont,
- 'ttf' : fontLoader.loadFont,
- 'woff' : fontLoader.loadFont,
- 'svg' : fontLoader.loadFont,
- 'ttc' : fontLoader.loadFont,
-
- 'default' : loadNothing
-};
-
-var ID = 'Loader';
-
-/**
- * The loader pipe, it can load several types of files:
- * 1. Images
- * 2. JSON
- * 3. Plist
- * 4. Audio
- * 5. Font
- * 6. Cocos Creator scene
- * It will not interfere with items of unknown type.
- * You can pass custom supported types in the constructor.
- * @class Pipeline.Loader
- */
-/**
- * Constructor of Loader, you can pass custom supported types.
- *
- * @method constructor
- * @param {Object} extMap Custom supported types with corresponded handler
- * @example
- *var loader = new Loader({
- * // This will match all url with `.scene` extension or all url with `scene` type
- * 'scene' : function (url, callback) {}
- *});
- */
-var Loader = function (extMap) {
- this.id = ID;
- this.async = true;
- this.pipeline = null;
-
- this.extMap = js.mixin(extMap, defaultMap);
-};
-Loader.ID = ID;
-
-/**
- * Add custom supported types handler or modify existing type handler.
- * @method addHandlers
- * @param {Object} extMap Custom supported types with corresponded handler
- */
-Loader.prototype.addHandlers = function (extMap) {
- this.extMap = js.mixin(this.extMap, extMap);
-};
-
-Loader.prototype.handle = function (item, callback) {
- var loadFunc = this.extMap[item.type] || this.extMap['default'];
- return loadFunc.call(this, item, callback);
-};
-
-Pipeline.Loader = module.exports = Loader;
diff --git a/cocos2d/core/load-pipeline/loading-items.js b/cocos2d/core/load-pipeline/loading-items.js
deleted file mode 100644
index d003cadde78..00000000000
--- a/cocos2d/core/load-pipeline/loading-items.js
+++ /dev/null
@@ -1,753 +0,0 @@
-/****************************************************************************
- Copyright (c) 2013-2016 Chukong Technologies Inc.
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-var CallbacksInvoker = require('../platform/callbacks-invoker');
-require('../utils/CCPath');
-var js = require('../platform/js');
-
-var _qid = (0|(Math.random()*998));
-var _queues = js.createMap(true);
-var _pool = [];
-var _POOL_MAX_LENGTH = 10;
-
-var ItemState = {
- WORKING: 1,
- COMPLETE: 2,
- ERROR: 3
-};
-
-var _queueDeps = js.createMap(true);
-
-function isIdValid (id) {
- var realId = id.url || id;
- return (typeof realId === 'string');
-}
-
-function _parseUrlParam (url) {
- if (!url) return undefined;
- var split = url.split('?');
- if (!split || !split[0] || !split[1]) {
- return undefined;
- }
- var urlParam = {};
- var queries = split[1].split('&');
- queries.forEach(function (item) {
- var itemSplit = item.split('=');
- urlParam[itemSplit[0]] = itemSplit[1];
- });
- return urlParam;
-}
-function createItem (id, queueId) {
- var url = (typeof id === 'object') ? id.url : id;
- var result = {
- queueId: queueId,
- id: url,
- url: url, // real download url, maybe changed
- rawUrl: undefined, // url used in scripts
- urlParam: _parseUrlParam(url),
- type: "",
- error: null,
- content: null,
- complete: false,
- states: {},
- deps: null
- };
-
- if (typeof id === 'object') {
- js.mixin(result, id);
- if (id.skips) {
- for (var i = 0; i < id.skips.length; i++) {
- var skip = id.skips[i];
- result.states[skip] = ItemState.COMPLETE;
- }
- }
- }
- result.rawUrl = result.url;
- if (url && !result.type) {
- result.type = cc.path.extname(url).toLowerCase().substr(1);
- }
- return result;
-}
-
-var checkedIds = [];
-function checkCircleReference(owner, item, recursiveCall) {
- if (!owner || !item) {
- return false;
- }
- var result = false;
- checkedIds.push(item.id);
- if (item.deps) {
- var i, deps = item.deps, subDep;
- for (i = 0; i < deps.length; i++) {
- subDep = deps[i];
- if (subDep.id === owner.id) {
- result = true;
- break;
- }
- else if (checkedIds.indexOf(subDep.id) >= 0) {
- continue;
- }
- else if (subDep.deps && checkCircleReference(owner, subDep, true)) {
- result = true;
- break;
- }
- }
- }
- if (!recursiveCall) {
- checkedIds.length = 0;
- }
- return result;
-}
-
-/**
- * !#en
- * LoadingItems is the queue of items which can flow them into the loading pipeline.
- * Please don't construct it directly, use {{#crossLink "LoadingItems.create"}}cc.LoadingItems.create{{/crossLink}} instead, because we use an internal pool to recycle the queues.
- * It hold a map of items, each entry in the map is a url to object key value pair.
- * Each item always contains the following property:
- * - id: The identification of the item, usually it's identical to url
- * - url: The url
- * - type: The type, it's the extension name of the url by default, could be specified manually too.
- * - error: The error happened in pipeline will be stored in this property.
- * - content: The content processed by the pipeline, the final result will also be stored in this property.
- * - complete: The flag indicate whether the item is completed by the pipeline.
- * - states: An object stores the states of each pipe the item go through, the state can be: Pipeline.ItemState.WORKING | Pipeline.ItemState.ERROR | Pipeline.ItemState.COMPLETE
- *
- * Item can hold other custom properties.
- * Each LoadingItems object will be destroyed for recycle after onComplete callback
- * So please don't hold its reference for later usage, you can copy properties in it though.
- * !#zh
- * LoadingItems 是一个加载对象队列,可以用来输送加载对象到加载管线中。
- * 请不要直接使用 new 构造这个类的对象,你可以使用 {{#crossLink "LoadingItems.create"}}cc.LoadingItems.create{{/crossLink}} 来创建一个新的加载队列,这样可以允许我们的内部对象池回收并重利用加载队列。
- * 它有一个 map 属性用来存放加载项,在 map 对象中已 url 为 key 值。
- * 每个对象都会包含下列属性:
- * - id:该对象的标识,通常与 url 相同。
- * - url:路径
- * - type: 类型,它这是默认的 URL 的扩展名,可以手动指定赋值。
- * - error:pipeline 中发生的错误将被保存在这个属性中。
- * - content: pipeline 中处理的临时结果,最终的结果也将被存储在这个属性中。
- * - complete:该标志表明该对象是否通过 pipeline 完成。
- * - states:该对象存储每个管道中对象经历的状态,状态可以是 Pipeline.ItemState.WORKING | Pipeline.ItemState.ERROR | Pipeline.ItemState.COMPLETE
- *
- * 对象可容纳其他自定义属性。
- * 每个 LoadingItems 对象都会在 onComplete 回调之后被销毁,所以请不要持有它的引用并在结束回调之后依赖它的内容执行任何逻辑,有这种需求的话你可以提前复制它的内容。
- *
- * @class LoadingItems
- * @extends CallbacksInvoker
- */
-var LoadingItems = function (pipeline, urlList, onProgress, onComplete) {
- CallbacksInvoker.call(this);
-
- this._id = ++_qid;
-
- _queues[this._id] = this;
-
- this._pipeline = pipeline;
-
- this._errorUrls = [];
-
- this._appending = false;
-
- this._ownerQueue = null;
-
- /**
- * !#en This is a callback which will be invoked while an item flow out the pipeline.
- * You can pass the callback function in LoadingItems.create or set it later.
- * !#zh 这个回调函数将在 item 加载结束后被调用。你可以在构造时传递这个回调函数或者是在构造之后直接设置。
- * @method onProgress
- * @param {Number} completedCount The number of the items that are already completed.
- * @param {Number} totalCount The total number of the items.
- * @param {Object} item The latest item which flow out the pipeline.
- * @example
- * loadingItems.onProgress = function (completedCount, totalCount, item) {
- * var progress = (100 * completedCount / totalCount).toFixed(2);
- * cc.log(progress + '%');
- * }
- */
- this.onProgress = onProgress;
-
- /**
- * !#en This is a callback which will be invoked while all items is completed,
- * You can pass the callback function in LoadingItems.create or set it later.
- * !#zh 该函数将在加载队列全部完成时被调用。你可以在构造时传递这个回调函数或者是在构造之后直接设置。
- * @method onComplete
- * @param {Array} errors All errored urls will be stored in this array, if no error happened, then it will be null
- * @param {LoadingItems} items All items.
- * @example
- * loadingItems.onComplete = function (errors, items) {
- * if (error)
- * cc.log('Completed with ' + errors.length + ' errors');
- * else
- * cc.log('Completed ' + items.totalCount + ' items');
- * }
- */
- this.onComplete = onComplete;
-
- /**
- * !#en The map of all items.
- * !#zh 存储所有加载项的对象。
- * @property map
- * @type {Object}
- */
- this.map = js.createMap(true);
-
- /**
- * !#en The map of completed items.
- * !#zh 存储已经完成的加载项。
- * @property completed
- * @type {Object}
- */
- this.completed = {};
-
- /**
- * !#en Total count of all items.
- * !#zh 所有加载项的总数。
- * @property totalCount
- * @type {Number}
- */
- this.totalCount = 0;
-
- /**
- * !#en Total count of completed items.
- * !#zh 所有完成加载项的总数。
- * @property completedCount
- * @type {Number}
- */
- this.completedCount = 0;
-
- /**
- * !#en Activated or not.
- * !#zh 是否启用。
- * @property active
- * @type {Boolean}
- */
- if (this._pipeline) {
- this.active = true;
- }
- else {
- this.active = false;
- }
-
- if (urlList) {
- if (urlList.length > 0) {
- this.append(urlList);
- }
- else {
- this.allComplete();
- }
- }
-};
-
-/**
- * !#en The item states of the LoadingItems, its value could be LoadingItems.ItemState.WORKING | LoadingItems.ItemState.COMPLETET | LoadingItems.ItemState.ERROR
- * !#zh LoadingItems 队列中的加载项状态,状态的值可能是 LoadingItems.ItemState.WORKING | LoadingItems.ItemState.COMPLETET | LoadingItems.ItemState.ERROR
- * @enum LoadingItems.ItemState
- */
-
-/**
- * @property {Number} WORKING
- */
-
-/**
- * @property {Number} COMPLETET
- */
-
-/**
- * @property {Number} ERROR
- */
-
-LoadingItems.ItemState = new cc.Enum(ItemState);
-
-/**
- * @class LoadingItems
- * @extends CallbacksInvoker
-*/
-
-/**
- * !#en The constructor function of LoadingItems, this will use recycled LoadingItems in the internal pool if possible.
- * You can pass onProgress and onComplete callbacks to visualize the loading process.
- * !#zh LoadingItems 的构造函数,这种构造方式会重用内部对象缓冲池中的 LoadingItems 队列,以尽量避免对象创建。
- * 你可以传递 onProgress 和 onComplete 回调函数来获知加载进度信息。
- * @method create
- * @static
- * @param {Pipeline} pipeline The pipeline to process the queue.
- * @param {Array} urlList The items array.
- * @param {Function} onProgress The progression callback, refer to {{#crossLink "LoadingItems.onProgress"}}{{/crossLink}}
- * @param {Function} onComplete The completion callback, refer to {{#crossLink "LoadingItems.onComplete"}}{{/crossLink}}
- * @return {LoadingItems} The LoadingItems queue object
- * @example
- * cc.LoadingItems.create(cc.loader, ['a.png', 'b.plist'], function (completedCount, totalCount, item) {
- * var progress = (100 * completedCount / totalCount).toFixed(2);
- * cc.log(progress + '%');
- * }, function (errors, items) {
- * if (errors) {
- * for (var i = 0; i < errors.length; ++i) {
- * cc.log('Error url: ' + errors[i] + ', error: ' + items.getError(errors[i]));
- * }
- * }
- * else {
- * var result_a = items.getContent('a.png');
- * // ...
- * }
- * })
- */
-LoadingItems.create = function (pipeline, urlList, onProgress, onComplete) {
- if (onProgress === undefined) {
- if (typeof urlList === 'function') {
- onComplete = urlList;
- urlList = onProgress = null;
- }
- }
- else if (onComplete === undefined) {
- if (typeof urlList === 'function') {
- onComplete = onProgress;
- onProgress = urlList;
- urlList = null;
- }
- else {
- onComplete = onProgress;
- onProgress = null;
- }
- }
-
- var queue = _pool.pop();
- if (queue) {
- queue._pipeline = pipeline;
- queue.onProgress = onProgress;
- queue.onComplete = onComplete;
- _queues[queue._id] = queue;
- if (queue._pipeline) {
- queue.active = true;
- }
- if (urlList) {
- queue.append(urlList);
- }
- }
- else {
- queue = new LoadingItems(pipeline, urlList, onProgress, onComplete);
- }
-
- return queue;
-};
-
-/**
- * !#en Retrieve the LoadingItems queue object for an item.
- * !#zh 通过 item 对象获取它的 LoadingItems 队列。
- * @method getQueue
- * @static
- * @param {Object} item The item to query
- * @return {LoadingItems} The LoadingItems queue object
- */
-LoadingItems.getQueue = function (item) {
- return item.queueId ? _queues[item.queueId] : null;
-};
-
-/**
- * !#en Complete an item in the LoadingItems queue, please do not call this method unless you know what's happening.
- * !#zh 通知 LoadingItems 队列一个 item 对象已完成,请不要调用这个函数,除非你知道自己在做什么。
- * @method itemComplete
- * @static
- * @param {Object} item The item which has completed
- */
-LoadingItems.itemComplete = function (item) {
- var queue = _queues[item.queueId];
- if (queue) {
- // console.log('----- Completed by pipeline ' + item.id + ', rest: ' + (queue.totalCount - queue.completedCount-1));
- queue.itemComplete(item.id);
- }
-};
-
-LoadingItems.initQueueDeps = function (queue) {
- var dep = _queueDeps[queue._id];
- if (!dep) {
- dep = _queueDeps[queue._id] = {
- completed: [],
- deps: []
- };
- }
- else {
- dep.completed.length = 0;
- dep.deps.length = 0;
- }
-};
-
-LoadingItems.registerQueueDep = function (owner, depId) {
- var queueId = owner.queueId || owner;
- if (!queueId) {
- return false;
- }
- var queueDepList = _queueDeps[queueId];
- // Owner is root queue
- if (queueDepList) {
- if (queueDepList.deps.indexOf(depId) === -1) {
- queueDepList.deps.push(depId);
- }
- }
- // Owner is an item in the intermediate queue
- else if (owner.id) {
- for (var id in _queueDeps) {
- var queue = _queueDeps[id];
- // Found root queue
- if (queue.deps.indexOf(owner.id) !== -1) {
- if (queue.deps.indexOf(depId) === -1) {
- queue.deps.push(depId);
- }
- }
- }
- }
-};
-
-LoadingItems.finishDep = function (depId) {
- for (var id in _queueDeps) {
- var queue = _queueDeps[id];
- // Found root queue
- if (queue.deps.indexOf(depId) !== -1 && queue.completed.indexOf(depId) === -1) {
- queue.completed.push(depId);
- }
- }
-};
-
-var proto = LoadingItems.prototype;
-js.mixin(proto, CallbacksInvoker.prototype);
-
-/**
- * !#en Add urls to the LoadingItems queue.
- * !#zh 向一个 LoadingItems 队列添加加载项。
- * @method append
- * @param {Array} urlList The url list to be appended, the url can be object or string
- * @return {Array} The accepted url list, some invalid items could be refused.
- */
-proto.append = function (urlList, owner) {
- if (!this.active) {
- return [];
- }
- if (owner && !owner.deps) {
- owner.deps = [];
- }
-
- this._appending = true;
- var accepted = [], i, url, item;
- for (i = 0; i < urlList.length; ++i) {
- url = urlList[i];
-
- // Already queued in another items queue, url is actually the item
- if (url.queueId && !this.map[url.id]) {
- this.map[url.id] = url;
- // Register item deps for circle reference check
- owner && owner.deps.push(url);
- // Queued and completed or Owner circle referenced by dependency
- if (url.complete || checkCircleReference(owner, url)) {
- this.totalCount++;
- // console.log('----- Completed already or circle referenced ' + url.id + ', rest: ' + (this.totalCount - this.completedCount-1));
- this.itemComplete(url.id);
- continue;
- }
- // Not completed yet, should wait it
- else {
- var self = this;
- var queue = _queues[url.queueId];
- if (queue) {
- this.totalCount++;
- LoadingItems.registerQueueDep(owner || this._id, url.id);
- // console.log('+++++ Waited ' + url.id);
- queue.addListener(url.id, function (item) {
- // console.log('----- Completed by waiting ' + item.id + ', rest: ' + (self.totalCount - self.completedCount-1));
- self.itemComplete(item.id);
- });
- }
- continue;
- }
- }
- // Queue new items
- if (isIdValid(url)) {
- item = createItem(url, this._id);
- var key = item.id;
- // No duplicated url
- if (!this.map[key]) {
- this.map[key] = item;
- this.totalCount++;
- // Register item deps for circle reference check
- owner && owner.deps.push(item);
- LoadingItems.registerQueueDep(owner || this._id, key);
- accepted.push(item);
- // console.log('+++++ Appended ' + item.id);
- }
- }
- }
- this._appending = false;
-
- // Manually complete
- if (this.completedCount === this.totalCount) {
- // console.log('===== All Completed ');
- this.allComplete();
- }
- else {
- this._pipeline.flowIn(accepted);
- }
- return accepted;
-};
-
-proto._childOnProgress = function (item) {
- if (this.onProgress) {
- var dep = _queueDeps[this._id];
- this.onProgress(dep ? dep.completed.length : this.completedCount, dep ? dep.deps.length : this.totalCount, item);
- }
-};
-
-/**
- * !#en Complete a LoadingItems queue, please do not call this method unless you know what's happening.
- * !#zh 完成一个 LoadingItems 队列,请不要调用这个函数,除非你知道自己在做什么。
- * @method allComplete
- */
-proto.allComplete = function () {
- var errors = this._errorUrls.length === 0 ? null : this._errorUrls;
- if (this.onComplete) {
- this.onComplete(errors, this);
- }
-};
-
-/**
- * !#en Check whether all items are completed.
- * !#zh 检查是否所有加载项都已经完成。
- * @method isCompleted
- * @return {Boolean}
- */
-proto.isCompleted = function () {
- return this.completedCount >= this.totalCount;
-};
-
-/**
- * !#en Check whether an item is completed.
- * !#zh 通过 id 检查指定加载项是否已经加载完成。
- * @method isItemCompleted
- * @param {String} id The item's id.
- * @return {Boolean}
- */
-proto.isItemCompleted = function (id) {
- return !!this.completed[id];
-};
-
-/**
- * !#en Check whether an item exists.
- * !#zh 通过 id 检查加载项是否存在。
- * @method exists
- * @param {String} id The item's id.
- * @return {Boolean}
- */
-proto.exists = function (id) {
- return !!this.map[id];
-};
-
-/**
- * !#en Returns the content of an internal item.
- * !#zh 通过 id 获取指定对象的内容。
- * @method getContent
- * @param {String} id The item's id.
- * @return {Object}
- */
-proto.getContent = function (id) {
- var item = this.map[id];
- var ret = null;
- if (item) {
- if (item.content) {
- ret = item.content;
- }
- else if (item.alias) {
- ret = item.alias.content;
- }
- }
-
- return ret;
-};
-
-/**
- * !#en Returns the error of an internal item.
- * !#zh 通过 id 获取指定对象的错误信息。
- * @method getError
- * @param {String} id The item's id.
- * @return {Object}
- */
-proto.getError = function (id) {
- var item = this.map[id];
- var ret = null;
- if (item) {
- if (item.error) {
- ret = item.error;
- } else if (item.alias) {
- ret = item.alias.error;
- }
- }
-
- return ret;
-};
-
-/**
- * !#en Add a listener for an item, the callback will be invoked when the item is completed.
- * !#zh 监听加载项(通过 key 指定)的完成事件。
- * @method addListener
- * @param {String} key
- * @param {Function} callback - can be null
- * @param {Object} target - can be null
- * @return {Boolean} whether the key is new
- */
-proto.addListener = CallbacksInvoker.prototype.add;
-
-/**
- * !#en
- * Check if the specified key has any registered callback.
- * If a callback is also specified, it will only return true if the callback is registered.
- * !#zh
- * 检查指定的加载项是否有完成事件监听器。
- * 如果同时还指定了一个回调方法,并且回调有注册,它只会返回 true。
- * @method hasListener
- * @param {String} key
- * @param {Function} [callback]
- * @param {Object} [target]
- * @return {Boolean}
- */
-proto.hasListener = CallbacksInvoker.prototype.has;
-
-/**
- * !#en
- * Removes a listener.
- * It will only remove when key, callback, target all match correctly.
- * !#zh
- * 移除指定加载项已经注册的完成事件监听器。
- * 只会删除 key, callback, target 均匹配的监听器。
- * @method remove
- * @param {String} key
- * @param {Function} callback
- * @param {Object} target
- * @return {Boolean} removed
- */
-proto.removeListener = CallbacksInvoker.prototype.remove;
-
-/**
- * !#en
- * Removes all callbacks registered in a certain event
- * type or all callbacks registered with a certain target.
- * !#zh 删除指定目标的所有完成事件监听器。
- * @method removeAllListeners
- * @param {String|Object} key - The event key to be removed or the target to be removed
- */
-proto.removeAllListeners = CallbacksInvoker.prototype.removeAll;
-
-/**
- * !#en Remove an item, can only remove completed item, ongoing item can not be removed.
- * !#zh 移除加载项,这里只会移除已经完成的加载项,正在进行的加载项将不能被删除。
- * @param {String} url
- */
-proto.removeItem = function (url) {
- var item = this.map[url];
- if (!item) return;
-
- if (!this.completed[item.alias || url]) return;
-
- delete this.completed[url];
- delete this.map[url];
- if (item.alias) {
- delete this.completed[item.alias.id];
- delete this.map[item.alias.id];
- }
-
- this.completedCount--;
- this.totalCount--;
-};
-
-/**
- * !#en Complete an item in the LoadingItems queue, please do not call this method unless you know what's happening.
- * !#zh 通知 LoadingItems 队列一个 item 对象已完成,请不要调用这个函数,除非你知道自己在做什么。
- * @method itemComplete
- * @param {String} id The item url
- */
-proto.itemComplete = function (id) {
- var item = this.map[id];
- if (!item) {
- return;
- }
-
- // Register or unregister errors
- var errorListId = this._errorUrls.indexOf(id);
- if (item.error && errorListId === -1) {
- this._errorUrls.push(id);
- }
- else if (!item.error && errorListId !== -1) {
- this._errorUrls.splice(errorListId, 1);
- }
-
- this.completed[id] = item;
- this.completedCount++;
-
- LoadingItems.finishDep(item.id);
- if (this.onProgress) {
- var dep = _queueDeps[this._id];
- this.onProgress(dep ? dep.completed.length : this.completedCount, dep ? dep.deps.length : this.totalCount, item);
- }
-
- this.invoke(id, item);
- this.removeAll(id);
-
- // All completed
- if (!this._appending && this.completedCount >= this.totalCount) {
- // console.log('===== All Completed ');
- this.allComplete();
- }
-};
-
-/**
- * !#en Destroy the LoadingItems queue, the queue object won't be garbage collected, it will be recycled, so every after destroy is not reliable.
- * !#zh 销毁一个 LoadingItems 队列,这个队列对象会被内部缓冲池回收,所以销毁后的所有内部信息都是不可依赖的。
- * @method destroy
- */
-proto.destroy = function () {
- this.active = false;
- this._appending = false;
- this._pipeline = null;
- this._ownerQueue = null;
- this._errorUrls.length = 0;
- this.onProgress = null;
- this.onComplete = null;
-
- this.map = js.createMap(true);
- this.completed = {};
-
- this.totalCount = 0;
- this.completedCount = 0;
-
- // Reinitialize CallbacksInvoker, generate three new objects, could be improved
- CallbacksInvoker.call(this);
-
- _queues[this._id] = null;
- if (_queueDeps[this._id]) {
- _queueDeps[this._id].completed.length = 0;
- _queueDeps[this._id].deps.length = 0;
- }
- if (_pool.indexOf(this) === -1 && _pool.length < _POOL_MAX_LENGTH) {
- _pool.push(this);
- }
-};
-
-cc.LoadingItems = module.exports = LoadingItems;
diff --git a/cocos2d/core/load-pipeline/md5-pipe.js b/cocos2d/core/load-pipeline/md5-pipe.js
deleted file mode 100644
index cc538d02420..00000000000
--- a/cocos2d/core/load-pipeline/md5-pipe.js
+++ /dev/null
@@ -1,88 +0,0 @@
-/****************************************************************************
- Copyright (c) 2016 Chukong Technologies Inc.
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-var Pipeline = require('./pipeline');
-
-const ID = 'MD5Pipe';
-const ExtnameRegex = /(\.[^.\n\\/]*)$/;
-const UuidRegex = /.*[/\\][0-9a-fA-F]{2}[/\\]([0-9a-fA-F-]{8,})/;
-
-function getUuidFromURL (url) {
- var matches = url.match(UuidRegex);
- if (matches) {
- return matches[1];
- }
- return "";
-}
-
-var MD5Pipe = function (md5AssetsMap, md5NativeAssetsMap, libraryBase) {
- this.id = ID;
- this.async = false;
- this.pipeline = null;
- this.md5AssetsMap = md5AssetsMap;
- this.md5NativeAssetsMap = md5NativeAssetsMap;
- this.libraryBase = libraryBase;
-};
-MD5Pipe.ID = ID;
-
-MD5Pipe.prototype.handle = function(item) {
- let hashPatchInFolder = false;
- // HACK: explicitly use folder md5 for ttf files
- if (item.type === 'ttf') {
- hashPatchInFolder = true;
- }
- item.url = this.transformURL(item.url, hashPatchInFolder);
- return item;
-};
-
-MD5Pipe.prototype.transformURL = function (url, hashPatchInFolder) {
- var uuid = getUuidFromURL(url);
- if (uuid) {
- var isNativeAsset = !url.startsWith(this.libraryBase);
- var map = isNativeAsset ? this.md5NativeAssetsMap : this.md5AssetsMap;
- let hashValue = map[uuid];
- if (hashValue) {
- if (hashPatchInFolder) {
- var dirname = cc.path.dirname(url);
- var basename = cc.path.basename(url);
- url = `${dirname}.${hashValue}/${basename}`;
- } else {
- var matched = false;
- url = url.replace(ExtnameRegex, (function(match, p1) {
- matched = true;
- return "." + hashValue + p1;
- }));
- if (!matched) {
- url = url + "." + hashValue;
- }
- }
- }
- }
- return url;
-};
-
-
-Pipeline.MD5Pipe = module.exports = MD5Pipe;
diff --git a/cocos2d/core/load-pipeline/pack-downloader.js b/cocos2d/core/load-pipeline/pack-downloader.js
deleted file mode 100644
index 8305c76e9fd..00000000000
--- a/cocos2d/core/load-pipeline/pack-downloader.js
+++ /dev/null
@@ -1,198 +0,0 @@
-/****************************************************************************
- Copyright (c) 2013-2016 Chukong Technologies Inc.
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-var Unpackers = require('./unpackers');
-var pushToMap = require('../utils/misc').pushToMap;
-
-// when more than one package contains the required asset,
-// choose to load from the package with the largest state value.
-var PackState = {
- Invalid: 0,
- Removed: 1,
- Downloading: 2,
- Loaded: 3,
-};
-
-function UnpackerData () {
- this.unpacker = null;
- this.state = PackState.Invalid;
-}
-
-// {assetUuid: packUuid|[packUuid]}
-// If value is array of packUuid, then the first one will be prioritized for download,
-// so the smallest pack must be at the beginning of the array.
-var uuidToPack = {};
-
-// {packUuid: assetIndices}
-var packIndices = {};
-
-// {packUuid: UnpackerData}
-// We have to cache all packs in global because for now there's no operation context in loader.
-var globalUnpackers = {};
-
-
-function error (uuid, packUuid) {
- return new Error('Can not retrieve ' + uuid + ' from packer ' + packUuid);
-}
-
-module.exports = {
- initPacks: function (packs) {
- packIndices = packs;
- for (var packUuid in packs) {
- var uuids = packs[packUuid];
- for (var i = 0; i < uuids.length; i++) {
- var uuid = uuids[i];
- // the smallest pack must be at the beginning of the array to download more first
- var pushFront = uuids.length === 1;
- pushToMap(uuidToPack, uuid, packUuid, pushFront);
- }
- }
- },
-
- _loadNewPack: function (uuid, packUuid, callback) {
- var self = this;
- var packUrl = cc.AssetLibrary.getLibUrlNoExt(packUuid) + '.json';
- cc.loader.load({ url: packUrl, ignoreMaxConcurrency: true }, function (err, packJson) {
- if (err) {
- cc.errorID(4916, uuid);
- return callback(err);
- }
- var res = self._doLoadNewPack(uuid, packUuid, packJson);
- if (res) {
- callback(null, res);
- }
- else {
- callback(error(uuid, packUuid));
- }
- });
- },
-
- _doPreload (packUuid, packJson) {
- var unpackerData = globalUnpackers[packUuid];
- if (!unpackerData) {
- unpackerData = globalUnpackers[packUuid] = new UnpackerData();
- unpackerData.state = PackState.Downloading;
- }
- if (unpackerData.state !== PackState.Loaded) {
- unpackerData.unpacker = new Unpackers.JsonUnpacker();
- unpackerData.unpacker.load(packIndices[packUuid], packJson);
- unpackerData.state = PackState.Loaded;
- }
- },
-
- _doLoadNewPack: function (uuid, packUuid, packedJson) {
- var unpackerData = globalUnpackers[packUuid];
- // double check cache after load
- if (unpackerData.state !== PackState.Loaded) {
- // init unpacker
- if (typeof packedJson === 'string') {
- packedJson = JSON.parse(packedJson);
- }
- if (Array.isArray(packedJson)) {
- unpackerData.unpacker = new Unpackers.JsonUnpacker();
- }
- else if (packedJson.type === Unpackers.TextureUnpacker.ID) {
- unpackerData.unpacker = new Unpackers.TextureUnpacker();
- }
- unpackerData.unpacker.load(packIndices[packUuid], packedJson);
- unpackerData.state = PackState.Loaded;
- }
-
- return unpackerData.unpacker.retrieve(uuid);
- },
-
- _selectLoadedPack: function (packUuids) {
- var existsPackState = PackState.Invalid;
- var existsPackUuid = '';
- for (var i = 0; i < packUuids.length; i++) {
- var packUuid = packUuids[i];
- var unpackerData = globalUnpackers[packUuid];
- if (unpackerData) {
- var state = unpackerData.state;
- if (state === PackState.Loaded) {
- return packUuid;
- }
- else if (state > existsPackState) { // load from the package with the largest state value,
- existsPackState = state;
- existsPackUuid = packUuid;
- }
- }
- }
- // otherwise the first one (smallest one) will be load
- return existsPackState !== PackState.Invalid ? existsPackUuid : packUuids[0];
- },
-
- /**
- * @returns {Object} When returns undefined, the requested item is not in any pack, when returns null, the item is in a loading pack, when item json exists, it will return the result directly.
- */
- load: function (item, callback) {
- var uuid = item.uuid;
- var packUuid = uuidToPack[uuid];
- if (!packUuid) {
- // Return undefined to let caller know it's not recognized.
- // We don't use false here because changing return value type may cause jit fail,
- // though return undefined may have the same issue.
- return;
- }
-
- if (Array.isArray(packUuid)) {
- packUuid = this._selectLoadedPack(packUuid);
- }
-
- var unpackerData = globalUnpackers[packUuid];
- if (unpackerData && unpackerData.state === PackState.Loaded) {
- // ensure async
- var json = unpackerData.unpacker.retrieve(uuid);
- if (json) {
- return json;
- }
- else {
- return error(uuid, packUuid);
- }
- }
- else {
- if (!unpackerData) {
- if (!CC_TEST) {
- console.log('Create unpacker %s for %s', packUuid, uuid);
- }
- unpackerData = globalUnpackers[packUuid] = new UnpackerData();
- unpackerData.state = PackState.Downloading;
- }
- this._loadNewPack(uuid, packUuid, callback);
- }
- // Return null to let caller know it's loading asynchronously
- return null;
- }
-};
-
-if (CC_TEST) {
- cc._Test.PackDownloader = module.exports;
- cc._Test.PackDownloader.reset = function () {
- uuidToPack = {};
- packIndices = {};
- globalUnpackers = {};
- };
-}
diff --git a/cocos2d/core/load-pipeline/pipeline.js b/cocos2d/core/load-pipeline/pipeline.js
deleted file mode 100644
index 1ee2df38524..00000000000
--- a/cocos2d/core/load-pipeline/pipeline.js
+++ /dev/null
@@ -1,407 +0,0 @@
-/****************************************************************************
- Copyright (c) 2013-2016 Chukong Technologies Inc.
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-var js = require('../platform/js');
-var LoadingItems = require('./loading-items');
-var ItemState = LoadingItems.ItemState;
-
-function flow (pipe, item) {
- var pipeId = pipe.id;
- var itemState = item.states[pipeId];
- var next = pipe.next;
- var pipeline = pipe.pipeline;
-
- if (item.error || itemState === ItemState.WORKING || itemState === ItemState.ERROR) {
- return;
- }
- else if (itemState === ItemState.COMPLETE) {
- if (next) {
- flow(next, item);
- }
- else {
- pipeline.flowOut(item);
- }
- }
- else {
- item.states[pipeId] = ItemState.WORKING;
- // Pass async callback in case it's a async call
- var result = pipe.handle(item, function (err, result) {
- if (err) {
- item.error = err;
- item.states[pipeId] = ItemState.ERROR;
- pipeline.flowOut(item);
- }
- else {
- // Result can be null, then it means no result for this pipe
- if (result) {
- item.content = result;
- }
- item.states[pipeId] = ItemState.COMPLETE;
- if (next) {
- flow(next, item);
- }
- else {
- pipeline.flowOut(item);
- }
- }
- });
- // If result exists (not undefined, null is ok), then we go with sync call flow
- if (result instanceof Error) {
- item.error = result;
- item.states[pipeId] = ItemState.ERROR;
- pipeline.flowOut(item);
- }
- else if (result !== undefined) {
- // Result can be null, then it means no result for this pipe
- if (result !== null) {
- item.content = result;
- }
- item.states[pipeId] = ItemState.COMPLETE;
- if (next) {
- flow(next, item);
- }
- else {
- pipeline.flowOut(item);
- }
- }
- }
-}
-
-/**
- * !#en
- * A pipeline describes a sequence of manipulations, each manipulation is called a pipe.
- * It's designed for loading process. so items should be urls, and the url will be the identity of each item during the process.
- * A list of items can flow in the pipeline and it will output the results of all pipes.
- * They flow in the pipeline like water in tubes, they go through pipe by pipe separately.
- * Finally all items will flow out the pipeline and the process is finished.
- *
- * !#zh
- * pipeline 描述了一系列的操作,每个操作都被称为 pipe。
- * 它被设计来做加载过程的流程管理。所以 item 应该是 url,并且该 url 将是在处理中的每个 item 的身份标识。
- * 一个 item 列表可以在 pipeline 中流动,它将输出加载项经过所有 pipe 之后的结果。
- * 它们穿过 pipeline 就像水在管子里流动,将会按顺序流过每个 pipe。
- * 最后当所有加载项都流出 pipeline 时,整个加载流程就结束了。
- * @class Pipeline
- */
-/**
- * !#en
- * Constructor, pass an array of pipes to construct a new Pipeline,
- * the pipes will be chained in the given order.
- * A pipe is an object which must contain an `id` in string and a `handle` function,
- * the id must be unique in the pipeline.
- * It can also include `async` property to identify whether it's an asynchronous process.
- * !#zh
- * 构造函数,通过一系列的 pipe 来构造一个新的 pipeline,pipes 将会在给定的顺序中被锁定。
- * 一个 pipe 就是一个对象,它包含了字符串类型的 ‘id’ 和 ‘handle’ 函数,在 pipeline 中 id 必须是唯一的。
- * 它还可以包括 ‘async’ 属性以确定它是否是一个异步过程。
- *
- * @method constructor
- * @param {Array} pipes
- * @example
- * var pipeline = new Pipeline([
- * {
- * id: 'Downloader',
- * handle: function (item, callback) {},
- * async: true
- * },
- * {id: 'Parser', handle: function (item) {}, async: false}
- * ]);
- */
-var Pipeline = function (pipes) {
- this._pipes = pipes;
- this._cache = js.createMap(true);
-
- for (var i = 0; i < pipes.length; ++i) {
- var pipe = pipes[i];
- // Must have handle and id, handle for flow, id for state flag
- if (!pipe.handle || !pipe.id) {
- continue;
- }
-
- pipe.pipeline = this;
- pipe.next = i < pipes.length - 1 ? pipes[i+1] : null;
- }
-};
-
-Pipeline.ItemState = ItemState;
-
-var proto = Pipeline.prototype;
-
-/**
- * !#en
- * Insert a new pipe at the given index of the pipeline.
- * A pipe must contain an `id` in string and a `handle` function, the id must be unique in the pipeline.
- * !#zh
- * 在给定的索引位置插入一个新的 pipe。
- * 一个 pipe 必须包含一个字符串类型的 ‘id’ 和 ‘handle’ 函数,该 id 在 pipeline 必须是唯一标识。
- * @method insertPipe
- * @param {Object} pipe The pipe to be inserted
- * @param {Number} index The index to insert
- */
-proto.insertPipe = function (pipe, index) {
- // Must have handle and id, handle for flow, id for state flag
- if (!pipe.handle || !pipe.id || index > this._pipes.length) {
- cc.warnID(4921);
- return;
- }
-
- if (this._pipes.indexOf(pipe) > 0) {
- cc.warnID(4922);
- return;
- }
-
- pipe.pipeline = this;
-
- var nextPipe = null;
- if (index < this._pipes.length) {
- nextPipe = this._pipes[index];
- }
-
- var previousPipe = null;
- if (index > 0) {
- previousPipe = this._pipes[index-1];
- }
-
- if (previousPipe) {
- previousPipe.next = pipe;
- }
- pipe.next = nextPipe;
-
- this._pipes.splice(index, 0, pipe);
-};
-
-/**
- * !en
- * Insert a pipe to the end of an existing pipe. The existing pipe must be a valid pipe in the pipeline.
- * !zh
- * 在当前 pipeline 的一个已知 pipe 后面插入一个新的 pipe。
- * @method insertPipeAfter
- * @param {Object} refPipe An existing pipe in the pipeline.
- * @param {Object} newPipe The pipe to be inserted.
- */
-proto.insertPipeAfter = function (refPipe, newPipe) {
- var index = this._pipes.indexOf(refPipe);
- if (index < 0) {
- return;
- }
- this.insertPipe(newPipe, index+1);
-};
-
-/**
- * !#en
- * Add a new pipe at the end of the pipeline.
- * A pipe must contain an `id` in string and a `handle` function, the id must be unique in the pipeline.
- * !#zh
- * 添加一个新的 pipe 到 pipeline 尾部。
- * 该 pipe 必须包含一个字符串类型 ‘id’ 和 ‘handle’ 函数,该 id 在 pipeline 必须是唯一标识。
- * @method appendPipe
- * @param {Object} pipe The pipe to be appended
- */
-proto.appendPipe = function (pipe) {
- // Must have handle and id, handle for flow, id for state flag
- if (!pipe.handle || !pipe.id) {
- return;
- }
-
- pipe.pipeline = this;
- pipe.next = null;
- if (this._pipes.length > 0) {
- this._pipes[this._pipes.length - 1].next = pipe;
- }
- this._pipes.push(pipe);
-};
-
-/**
- * !#en
- * Let new items flow into the pipeline.
- * Each item can be a simple url string or an object,
- * if it's an object, it must contain `id` property.
- * You can specify its type by `type` property, by default, the type is the extension name in url.
- * By adding a `skips` property including pipe ids, you can skip these pipe.
- * The object can contain any supplementary property as you want.
- * !#zh
- * 让新的 item 流入 pipeline 中。
- * 这里的每个 item 可以是一个简单字符串类型的 url 或者是一个对象,
- * 如果它是一个对象的话,他必须要包含 ‘id’ 属性。
- * 你也可以指定它的 ‘type’ 属性类型,默认情况下,该类型是 ‘url’ 的后缀名。
- * 也通过添加一个 包含 ‘skips’ 属性的 item 对象,你就可以跳过 skips 中包含的 pipe。
- * 该对象可以包含任何附加属性。
- * @method flowIn
- * @param {Array} items
- * @example
- * pipeline.flowIn([
- * 'res/Background.png',
- * {
- * id: 'res/scene.json',
- * type: 'scene',
- * name: 'scene',
- * skips: ['Downloader']
- * }
- * ]);
- */
-proto.flowIn = function (items) {
- var i, pipe = this._pipes[0], item;
- if (pipe) {
- // Cache all items first, in case synchronous loading flow same item repeatly
- for (i = 0; i < items.length; i++) {
- item = items[i];
- this._cache[item.id] = item;
- }
- for (i = 0; i < items.length; i++) {
- item = items[i];
- flow(pipe, item);
- }
- }
- else {
- for (i = 0; i < items.length; i++) {
- this.flowOut(items[i]);
- }
- }
-};
-
-/*
- * !#en
- * Let new items flow into the pipeline and give a callback when the list of items are all completed.
- * This is for loading dependencies for an existing item in flow, usually used in a pipe logic.
- * For example, we have a loader for scene configuration file in JSON, the scene will only be fully loaded
- * after all its dependencies are loaded, then you will need to use function to flow in all dependencies
- * found in the configuration file, and finish the loader pipe only after all dependencies are loaded (in the callback).
- * !#zh
- * 让新 items 流入 pipeline 并且当 item 列表完成时进行回调函数。
- * 这个 API 的使用通常是为了加载依赖项。
- * 例如:
- * 我们需要加载一个场景配置的 JSON 文件,该场景会将所有的依赖项全部都加载完毕以后,进行回调表示加载完毕。
- * @method flowInDeps
- * @deprecated since v1.3
- * @param {Array} urlList
- * @param {Function} callback
- * @return {Array} Items accepted by the pipeline
- */
-proto.flowInDeps = function (owner, urlList, callback) {
- var deps = LoadingItems.create(this, function (errors, items) {
- callback(errors, items);
- items.destroy();
- });
- return deps.append(urlList, owner);
-};
-
-proto.flowOut = function (item) {
- if (item.error) {
- delete this._cache[item.id];
- }
- else if (!this._cache[item.id]) {
- this._cache[item.id] = item;
- }
- item.complete = true;
- LoadingItems.itemComplete(item);
-};
-
-/**
- * !#en
- * Copy the item states from one source item to all destination items.
- * It's quite useful when a pipe generate new items from one source item,
- * then you should flowIn these generated items into pipeline,
- * but you probably want them to skip all pipes the source item already go through,
- * you can achieve it with this API.
- *
- * For example, an unzip pipe will generate more items, but you won't want them to pass unzip or download pipe again.
- * !#zh
- * 从一个源 item 向所有目标 item 复制它的 pipe 状态,用于避免重复通过部分 pipe。
- * 当一个源 item 生成了一系列新的 items 时很有用,
- * 你希望让这些新的依赖项进入 pipeline,但是又不希望它们通过源 item 已经经过的 pipe,
- * 但是你可能希望他们源 item 已经通过并跳过所有 pipes,
- * 这个时候就可以使用这个 API。
- * @method copyItemStates
- * @param {Object} srcItem The source item
- * @param {Array|Object} dstItems A single destination item or an array of destination items
- */
-proto.copyItemStates = function (srcItem, dstItems) {
- if (!(dstItems instanceof Array)) {
- dstItems.states = srcItem.states;
- return;
- }
- for (var i = 0; i < dstItems.length; ++i) {
- dstItems[i].states = srcItem.states;
- }
-};
-
-/**
- * !#en Returns an item in pipeline.
- * !#zh 根据 id 获取一个 item
- * @method getItem
- * @param {Object} id The id of the item
- * @return {Object}
- */
-proto.getItem = function (id) {
- var item = this._cache[id];
-
- if (!item)
- return item;
-
- // downloader.js downloadUuid
- if (item.alias)
- item = item.alias;
-
- return item;
-};
-
-/**
- * !#en Removes an completed item in pipeline.
- * It will only remove the cache in the pipeline or loader, its dependencies won't be released.
- * cc.loader provided another method to completely cleanup the resource and its dependencies,
- * please refer to {{#crossLink "loader/release:method"}}cc.loader.release{{/crossLink}}
- * !#zh 移除指定的已完成 item。
- * 这将仅仅从 pipeline 或者 loader 中删除其缓存,并不会释放它所依赖的资源。
- * cc.loader 中提供了另一种删除资源及其依赖的清理方法,请参考 {{#crossLink "loader/release:method"}}cc.loader.release{{/crossLink}}
- * @method removeItem
- * @param {Object} id The id of the item
- * @return {Boolean} succeed or not
- */
-proto.removeItem = function (id) {
- var removed = this._cache[id];
- if (removed && removed.complete) {
- delete this._cache[id];
- }
- return removed;
-};
-
-/**
- * !#en Clear the current pipeline, this function will clean up the items.
- * !#zh 清空当前 pipeline,该函数将清理 items。
- * @method clear
- */
-proto.clear = function () {
- for (var id in this._cache) {
- var item = this._cache[id];
- delete this._cache[id];
- if (!item.complete) {
- item.error = new Error('Canceled manually');
- this.flowOut(item);
- }
- }
-};
-
-cc.Pipeline = module.exports = Pipeline;
diff --git a/cocos2d/core/load-pipeline/released-asset-checker.js b/cocos2d/core/load-pipeline/released-asset-checker.js
deleted file mode 100644
index 6092847c278..00000000000
--- a/cocos2d/core/load-pipeline/released-asset-checker.js
+++ /dev/null
@@ -1,114 +0,0 @@
-/****************************************************************************
- Copyright (c) 2013-2016 Chukong Technologies Inc.
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-if (CC_DEBUG) {
-
-var js = require('../platform/js');
-
-// checks if asset was releasable
-
-function ReleasedAssetChecker () {
- // { dependKey: true }
- this._releasedKeys = js.createMap(true);
- this._dirty = false;
-}
-
-// mark as released for further checking dependencies
-ReleasedAssetChecker.prototype.setReleased = function (item, releasedKey) {
- this._releasedKeys[releasedKey] = true;
- this._dirty = true;
-};
-
-var tmpInfo = null;
-function getItemDesc (item) {
- if (item.uuid) {
- if (!tmpInfo) {
- tmpInfo = { path: "", type: null };
- }
- if (cc.loader._resources._getInfo_DEBUG(item.uuid, tmpInfo)) {
- tmpInfo.path = 'resources/' + tmpInfo.path;
- return `"${tmpInfo.path}" (type: ${js.getClassName(tmpInfo.type)}, uuid: ${item.uuid})`;
- }
- else {
- return `"${item.rawUrl}" (${item.uuid})`;
- }
- }
- else {
- return `"${item.rawUrl}"`;
- }
-}
-
-function doCheckCouldRelease (releasedKey, refOwnerItem, caches) {
- var loadedAgain = caches[releasedKey];
- if (!loadedAgain) {
- cc.log(`"${releasedKey}" was released but maybe still referenced by ${getItemDesc(refOwnerItem)}`);
- }
-}
-
-// check dependencies
-ReleasedAssetChecker.prototype.checkCouldRelease = function (caches) {
- if (!this._dirty) {
- return;
- }
- this._dirty = false;
-
- var released = this._releasedKeys;
-
- // check loader cache
- for (let id in caches) {
- var item = caches[id];
- if (item.alias) {
- item = item.alias;
- }
- let depends = item.dependKeys;
- if (depends) {
- for (let i = 0; i < depends.length; ++i) {
- let depend = depends[i];
- if (released[depend]) {
- doCheckCouldRelease(depend, item, caches);
- delete released[depend];
- }
- }
- }
- }
-
- // // check current scene
- // let depends = cc.director.getScene().dependAssets;
- // for (let i = 0; i < depends.length; ++i) {
- // let depend = depends[i];
- // if (released[depend]) {
- // doCheckCouldRelease(depend, item, caches);
- // delete released[depend];
- // }
- // }
-
- // clear released
- js.clear(released);
-};
-
-module.exports = ReleasedAssetChecker;
-
-}
diff --git a/cocos2d/core/load-pipeline/unpackers.js b/cocos2d/core/load-pipeline/unpackers.js
deleted file mode 100644
index 77913d55fbe..00000000000
--- a/cocos2d/core/load-pipeline/unpackers.js
+++ /dev/null
@@ -1,94 +0,0 @@
-/****************************************************************************
- Copyright (c) 2013-2016 Chukong Technologies Inc.
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-var Texture2D = require('../assets/CCTexture2D');
-var js = require('../platform/js');
-
-function JsonUnpacker () {
- this.jsons = {};
-}
-
-/**
- * @param {String[]} indices
- * @param {Object[]} packedJson
- */
-JsonUnpacker.prototype.load = function (indices, packedJson) {
- if (packedJson.length !== indices.length) {
- cc.errorID(4915);
- }
- for (var i = 0; i < indices.length; i++) {
- var key = indices[i];
- var json = packedJson[i];
- this.jsons[key] = json;
- }
-};
-
-JsonUnpacker.prototype.retrieve = function (key) {
- return this.jsons[key] || null;
-};
-
-
-function TextureUnpacker () {
- this.contents = {};
-}
-TextureUnpacker.ID = js._getClassId(Texture2D);
-
-/**
- * @param {String[]} indices
- * @param {Object[]} packedJson
- */
-TextureUnpacker.prototype.load = function (indices, packedJson) {
- var datas = packedJson.data.split('|');
- if (datas.length !== indices.length) {
- cc.errorID(4915);
- }
- for (var i = 0; i < indices.length; i++) {
- this.contents[indices[i]] = datas[i];
- }
-};
-
-TextureUnpacker.prototype.retrieve = function (key) {
- var content = this.contents[key];
- if (content) {
- return {
- __type__: TextureUnpacker.ID,
- content: content
- };
- }
- else {
- return null;
- }
-};
-
-if (CC_TEST) {
- cc._Test.JsonUnpacker = JsonUnpacker;
- cc._Test.TextureUnpacker = TextureUnpacker;
-}
-
-module.exports = {
- JsonUnpacker,
- TextureUnpacker,
-};
diff --git a/cocos2d/core/load-pipeline/uuid-loader.js b/cocos2d/core/load-pipeline/uuid-loader.js
deleted file mode 100644
index 153bb196c2e..00000000000
--- a/cocos2d/core/load-pipeline/uuid-loader.js
+++ /dev/null
@@ -1,294 +0,0 @@
-/****************************************************************************
- Copyright (c) 2013-2016 Chukong Technologies Inc.
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-const js = require('../platform/js');
-const debug = require('../CCDebug');
-require('../platform/deserialize');
-const LoadingItems = require('./loading-items');
-
-function isSceneObj (json) {
- var SCENE_ID = 'cc.Scene';
- var PREFAB_ID = 'cc.Prefab';
- return json && (
- (json[0] && json[0].__type__ === SCENE_ID) ||
- (json[1] && json[1].__type__ === SCENE_ID) ||
- (json[0] && json[0].__type__ === PREFAB_ID)
- );
-}
-
-function parseDepends (item, asset, tdInfo, deferredLoadRawAssetsInRuntime) {
- var uuidList = tdInfo.uuidList;
- var objList = tdInfo.uuidObjList;
- var propList = tdInfo.uuidPropList;
- var stillUseUrl = tdInfo._stillUseUrl;
- var depends;
- var i, dependUuid;
- // cache dependencies for auto release
- var dependKeys = item.dependKeys = [];
-
- if (deferredLoadRawAssetsInRuntime) {
- depends = [];
- // parse depends assets
- for (i = 0; i < uuidList.length; i++) {
- dependUuid = uuidList[i];
- var obj = objList[i];
- var prop = propList[i];
- var info = cc.AssetLibrary._getAssetInfoInRuntime(dependUuid);
- if (info.raw) {
- // skip preloading raw assets
- var url = info.url;
- obj[prop] = url;
- dependKeys.push(url);
- }
- else {
- // declare depends assets
- depends.push({
- type: 'uuid',
- uuid: dependUuid,
- deferredLoadRaw: true,
- _owner: obj,
- _ownerProp: prop,
- _stillUseUrl: stillUseUrl[i]
- });
- }
- }
- }
- else {
- depends = new Array(uuidList.length);
-
- // declare depends assets
- for (i = 0; i < uuidList.length; i++) {
- dependUuid = uuidList[i];
- depends[i] = {
- type: 'uuid',
- uuid: dependUuid,
- _owner: objList[i],
- _ownerProp: propList[i],
- _stillUseUrl: stillUseUrl[i]
- };
- }
-
- // load native object (Image/Audio) as depends
- if (asset._native && !asset.constructor.preventPreloadNativeObject) {
- depends.push({
- url: asset.nativeUrl,
- _owner: asset,
- _ownerProp: '_nativeAsset',
- });
- }
- }
-
- return depends;
-}
-
-function loadDepends (pipeline, item, asset, depends, callback) {
- // Predefine content for dependencies usage
- item.content = asset;
- var dependKeys = item.dependKeys;
- pipeline.flowInDeps(item, depends, function (errors, items) {
- var item, missingAssetReporter;
- var itemsMap = items.map;
- for (var src in itemsMap) {
- item = itemsMap[src];
- if (item.uuid && item.content) {
- item.content._uuid = item.uuid;
- }
- }
- for (var i = 0; i < depends.length; i++) {
- var dep = depends[i];
- var dependSrc = dep.uuid;
- var dependUrl = dep.url;
- var dependObj = dep._owner;
- var dependProp = dep._ownerProp;
- item = itemsMap[dependUrl];
- if (!item) {
- continue;
- }
-
- var loadCallbackCtx = dep;
- function loadCallback (item) {
- var value = item.content;
- if (this._stillUseUrl) {
- value = (value && cc.RawAsset.wasRawAssetType(value.constructor)) ? value.nativeUrl : item.rawUrl;
- }
- this._owner[this._ownerProp] = value;
- if (item.uuid !== asset._uuid && dependKeys.indexOf(item.id) < 0) {
- dependKeys.push(item.id);
- }
- }
-
- if (item.complete || item.content) {
- if (item.error) {
- if (CC_EDITOR && item.error.errorCode === 'db.NOTFOUND') {
- if (!missingAssetReporter) {
- var MissingObjectReporter = Editor.require('app://editor/page/scene-utils/missing-object-reporter');
- missingAssetReporter = new MissingObjectReporter(asset);
- }
- missingAssetReporter.stashByOwner(dependObj, dependProp, Editor.serialize.asAsset(dependSrc));
- }
- else {
- cc._throw(item.error);
- }
- }
- else {
- loadCallback.call(loadCallbackCtx, item);
- }
- }
- else {
- // item was removed from cache, but ready in pipeline actually
- var queue = LoadingItems.getQueue(item);
- // Hack to get a better behavior
- var list = queue._callbackTable[dependSrc];
- if (list) {
- list.unshift(loadCallback, loadCallbackCtx);
- }
- else {
- queue.addListener(dependSrc, loadCallback, loadCallbackCtx);
- }
- }
- }
- // Emit dependency errors in runtime, but not in editor,
- // because editor need to open the scene / prefab to let user fix missing asset issues
- if (CC_EDITOR && missingAssetReporter) {
- missingAssetReporter.reportByOwner();
- callback(null, asset);
- }
- else {
- callback(errors, asset);
- }
- });
-}
-
-// can deferred load raw assets in runtime
-function canDeferredLoad (asset, item, isScene) {
- if (CC_EDITOR) {
- return false;
- }
- var res = item.deferredLoadRaw;
- if (res) {
- // check if asset support deferred
- if ((asset instanceof cc.Asset) && asset.constructor.preventDeferredLoadDependents) {
- res = false;
- }
- }
- else if (isScene) {
- if (asset instanceof cc.SceneAsset || asset instanceof cc.Prefab) {
- res = asset.asyncLoadAssets;
- //if (res) {
- // cc.log('deferred load raw assets for ' + item.id);
- //}
- }
- }
- return res;
-}
-
-var MissingClass;
-
-function loadUuid (item, callback) {
- if (CC_EDITOR) {
- MissingClass = MissingClass || Editor.require('app://editor/page/scene-utils/missing-class-reporter').MissingClass;
- }
-
- var json;
- if (typeof item.content === 'string') {
- try {
- json = JSON.parse(item.content);
- }
- catch (e) {
- return new Error(debug.getError(4923, item.id, e.stack));
- }
- }
- else if (typeof item.content === 'object') {
- json = item.content;
- }
- else {
- return new Error(debug.getError(4924));
- }
-
- var classFinder;
- var isScene = isSceneObj(json);
- if (isScene) {
- if (CC_EDITOR) {
- MissingClass.hasMissingClass = false;
- classFinder = function (type, data, owner, propName) {
- var res = MissingClass.classFinder(type, data, owner, propName);
- if (res) {
- return res;
- }
- return cc._MissingScript.getMissingWrapper(type, data);
- };
- classFinder.onDereferenced = MissingClass.classFinder.onDereferenced;
- }
- else {
- classFinder = cc._MissingScript.safeFindClass;
- }
- }
- else {
- classFinder = function (id) {
- var cls = js._getClassById(id);
- if (cls) {
- return cls;
- }
- cc.warnID(4903, id);
- return Object;
- };
- }
-
- var tdInfo = cc.deserialize.Details.pool.get();
-
- var asset;
- try {
- asset = cc.deserialize(json, tdInfo, {
- classFinder: classFinder,
- target: item.existingAsset,
- customEnv: item
- });
- }
- catch (e) {
- cc.deserialize.Details.pool.put(tdInfo);
- var err = CC_JSB ? (e + '\n' + e.stack) : e.stack;
- return new Error(debug.getError(4925, item.id, err));
- }
-
- asset._uuid = item.uuid;
-
- if (CC_EDITOR && isScene && MissingClass.hasMissingClass) {
- MissingClass.reportMissingClass(asset);
- }
-
- var deferredLoad = canDeferredLoad(asset, item, isScene);
- var depends = parseDepends(item, asset, tdInfo, deferredLoad);
-
- cc.deserialize.Details.pool.put(tdInfo);
-
- if (depends.length === 0) {
- return callback(null, asset);
- }
- loadDepends(this.pipeline, item, asset, depends, callback);
-}
-
-module.exports = loadUuid;
-loadUuid.isSceneObj = isSceneObj;
diff --git a/cocos2d/core/mesh/CCMesh.js b/cocos2d/core/mesh/CCMesh.js
index e675d2806b6..552b494689e 100644
--- a/cocos2d/core/mesh/CCMesh.js
+++ b/cocos2d/core/mesh/CCMesh.js
@@ -24,8 +24,11 @@
****************************************************************************/
const renderer = require('../renderer');
-const renderEngine = require('../renderer/render-engine');
-const gfx = renderEngine.gfx;
+const EventTarget = require('../event/event-target');
+
+import InputAssembler from '../../renderer/core/input-assembler';
+import gfx from '../../renderer/gfx';
+import { Primitive, VertexBundle, MeshData} from './mesh-data';
function applyColor (data, offset, value) {
data[offset] = value._val;
@@ -33,40 +36,85 @@ function applyColor (data, offset, value) {
function applyVec2 (data, offset, value) {
data[offset] = value.x;
- data[offset+1] = value.y;
+ data[offset + 1] = value.y;
}
function applyVec3 (data, offset, value) {
data[offset] = value.x;
- data[offset+1] = value.y;
- data[offset+2] = value.z;
+ data[offset + 1] = value.y;
+ data[offset + 2] = value.z;
}
+const _compType2fn = {
+ 5120: 'getInt8',
+ 5121: 'getUint8',
+ 5122: 'getInt16',
+ 5123: 'getUint16',
+ 5124: 'getInt32',
+ 5125: 'getUint32',
+ 5126: 'getFloat32',
+};
+
+const _compType2write = {
+ 5120: 'setInt8',
+ 5121: 'setUint8',
+ 5122: 'setInt16',
+ 5123: 'setUint16',
+ 5124: 'setInt32',
+ 5125: 'setUint32',
+ 5126: 'setFloat32',
+};
+
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView#Endianness
+const littleEndian = (function () {
+ let buffer = new ArrayBuffer(2);
+ new DataView(buffer).setInt16(0, 256, true);
+ // Int16Array uses the platform's endianness.
+ return new Int16Array(buffer)[0] === 256;
+})();
- /**
- * @module cc
- */
+/**
+* @module cc
+*/
/**
* !#en Mesh Asset.
* !#zh 网格资源。
* @class Mesh
* @extends Asset
+ * @uses EventTarget
*/
-var Mesh = cc.Class({
+let Mesh = cc.Class({
name: 'cc.Mesh',
extends: cc.Asset,
+ mixins: [EventTarget],
properties: {
- _modelSetter: {
- set: function (model) {
- this._initWithModel(model);
+ _nativeAsset: {
+ override: true,
+ get () {
+ return this._buffer;
+ },
+ set (bin) {
+ this._buffer = ArrayBuffer.isView(bin) ? bin.buffer : bin;
+ this.initWithBuffer();
}
},
+ _vertexBundles: {
+ default: null,
+ type: VertexBundle
+ },
+ _primitives: {
+ default: null,
+ Primitive
+ },
+ _minPos: cc.v3(),
+ _maxPos: cc.v3(),
+
/**
* !#en Get ir set the sub meshes.
* !#zh 设置或者获取子网格。
- * @property {[renderEngine.InputAssembler]} subMeshes
+ * @property {[InputAssembler]} subMeshes
*/
subMeshes: {
get () {
@@ -75,18 +123,80 @@ var Mesh = cc.Class({
set (v) {
this._subMeshes = v;
}
+ },
+
+ subDatas : {
+ get () {
+ return this._subDatas;
+ }
}
},
ctor () {
- this._modelUuid = '';
- this._meshID = -1;
- this._model = null;
-
this._subMeshes = [];
+ this._subDatas = [];
+ this.loaded = false;
+ },
+
+ initWithBuffer () {
+ this._subMeshes.length = 0;
- this._ibs = [];
- this._vbs = [];
+ let primitives = this._primitives;
+ for (let i = 0; i < primitives.length; i++) {
+ let primitive = primitives[i];
+
+ // ib
+ let ibrange = primitive.data;
+ let ibData = new Uint8Array(this._buffer, ibrange.offset, ibrange.length);
+
+ // vb
+ let vertexBundle = this._vertexBundles[primitive.vertexBundleIndices[0]];
+ let vbRange = vertexBundle.data;
+ let gfxVFmt = new gfx.VertexFormat(vertexBundle.formats);
+ // Mesh binary may have several data format, must use Uint8Array to store data.
+ let vbData = new Uint8Array(this._buffer, vbRange.offset, vbRange.length);
+
+ let canBatch = this._canVertexFormatBatch(gfxVFmt);
+
+ let meshData = new MeshData();
+ meshData.vData = vbData;
+ meshData.iData = ibData;
+ meshData.vfm = gfxVFmt;
+ meshData.offset = vbRange.offset;
+ meshData.canBatch = canBatch;
+ this._subDatas.push(meshData);
+
+ if (CC_JSB && CC_NATIVERENDERER) {
+ meshData.vDirty = true;
+ } else {
+ let vbBuffer = new gfx.VertexBuffer(
+ renderer.device,
+ gfxVFmt,
+ gfx.USAGE_STATIC,
+ vbData
+ );
+
+ let ibBuffer = new gfx.IndexBuffer(
+ renderer.device,
+ primitive.indexUnit,
+ gfx.USAGE_STATIC,
+ ibData
+ );
+
+ // create sub meshes
+ this._subMeshes.push(new InputAssembler(vbBuffer, ibBuffer));
+ }
+ }
+ this.loaded = true;
+ this.emit('load');
+ },
+
+ _canVertexFormatBatch (format) {
+ let aPosition = format._attr2el[gfx.ATTR_POSITION];
+ let canBatch = !aPosition ||
+ (aPosition.type === gfx.ATTR_TYPE_FLOAT32 &&
+ format._bytes % 4 === 0);
+ return canBatch;
},
/**
@@ -97,74 +207,121 @@ var Mesh = cc.Class({
* @method init
* @param {gfx.VertexFormat} vertexFormat - vertex format
* @param {Number} vertexCount - how much vertex should be create in this buffer.
- * @param {Boolean} dynamic - whether or not to use dynamic buffer.
+ * @param {Boolean} [dynamic] - whether or not to use dynamic buffer.
+ * @param {Boolean} [index]
*/
- init (vertexFormat, vertexCount, dynamic) {
- this.clear();
+ init (vertexFormat, vertexCount, dynamic = false, index = 0) {
+ let data = new Uint8Array(vertexFormat._bytes * vertexCount);
+ let meshData = new MeshData();
+ meshData.vData = data;
+ meshData.vfm = vertexFormat;
+ meshData.vDirty = true;
+ meshData.canBatch = this._canVertexFormatBatch(vertexFormat);
+
+ if (!(CC_JSB && CC_NATIVERENDERER)) {
+ let vb = new gfx.VertexBuffer(
+ renderer.device,
+ vertexFormat,
+ dynamic ? gfx.USAGE_DYNAMIC : gfx.USAGE_STATIC,
+ data,
+ );
+
+ meshData.vb = vb;
+ this._subMeshes[index] = new InputAssembler(meshData.vb);
+ }
+
+ let oldSubData = this._subDatas[index];
+ if (oldSubData) {
+ if (oldSubData.vb) {
+ oldSubData.vb.destroy();
+ }
+ if (oldSubData.ib) {
+ oldSubData.ib.destroy();
+ }
+ }
+
+ this._subDatas[index] = meshData;
- let data = new Uint8Array(vertexFormat._bytes*vertexCount);
- let vb = new gfx.VertexBuffer(
- renderer.device,
- vertexFormat,
- dynamic ? gfx.USAGE_STATIC : gfx.USAGE_DYNAMIC,
- data,
- vertexCount
- );
-
- this._vbs[0] = {
- buffer: vb,
- data: data,
- float32Data: new Float32Array(data.buffer),
- uint32Data: new Uint32Array(data.buffer),
- dirty: true
- };
+ this.loaded = true;
+ this.emit('load');
+ this.emit('init-format');
},
-
+
/**
* !#en
* Set the vertex values.
* !#zh
* 设置顶点数据
- * @method setVertexes
+ * @method setVertices
* @param {String} name - the attribute name, e.g. gfx.ATTR_POSITION
- * @param {[Vec2|Vec3|Color]} values - the vertex values
- * @param {Number} [index]
+ * @param {[Vec2] | [Vec3] | [Color] | [Number] | Uint8Array | Float32Array} values - the vertex values
*/
- setVertexes (name, values, index) {
+ setVertices (name, values, index) {
index = index || 0;
- let vb = this._vbs[index];
+ let subData = this._subDatas[index];
- let buffer = vb.buffer;
- let el = buffer._format._attr2el[name];
+ let el = subData.vfm.element(name);
if (!el) {
return cc.warn(`Cannot find ${name} attribute in vertex defines.`);
}
- let stride = el.stride/4;
- let offset = el.offset/4;
+ // whether the values is expanded
+ let isFlatMode = typeof values[0] === 'number';
+
+ let elNum = el.num;
+ let verticesCount = isFlatMode ? ((values.length / elNum) | 0) : values.length;
+ if (subData.vData.byteLength < verticesCount * el.stride) {
+ subData.setVData(new Uint8Array(verticesCount * subData.vfm._bytes));
+ }
let data;
- let applyFunc;
+ let bytes = 4;
if (name === gfx.ATTR_COLOR) {
- data = vb.uint32Data;
- applyFunc = applyColor;
+ if (!isFlatMode) {
+ data = subData.getVData(Uint32Array);
+ }
+ else {
+ data = subData.getVData();
+ bytes = 1;
+ }
+ }
+ else {
+ data = subData.getVData(Float32Array);
+ }
+
+ let stride = el.stride / bytes;
+ let offset = el.offset / bytes;
+
+ if (isFlatMode) {
+ for (let i = 0, l = (values.length / elNum); i < l; i++) {
+ let sOffset = i * elNum;
+ let dOffset = i * stride + offset;
+ for (let j = 0; j < elNum; j++) {
+ data[dOffset + j] = values[sOffset + j];
+ }
+ }
}
else {
- data = vb.float32Data;
- if (el.num === 2) {
- applyFunc = applyVec2;
+ let applyFunc;
+ if (name === gfx.ATTR_COLOR) {
+ applyFunc = applyColor;
}
else {
- applyFunc = applyVec3;
+ if (elNum === 2) {
+ applyFunc = applyVec2;
+ }
+ else {
+ applyFunc = applyVec3;
+ }
}
- }
- for (let i = 0, l = values.length; i < l; i++) {
- let v = values[i];
- let vOffset = i * stride + offset;
- applyFunc(data, vOffset, v);
+ for (let i = 0, l = values.length; i < l; i++) {
+ let v = values[i];
+ let vOffset = i * stride + offset;
+ applyFunc(data, vOffset, v);
+ }
}
- vb.dirty = true;
+ subData.vDirty = true;
},
/**
@@ -173,39 +330,65 @@ var Mesh = cc.Class({
* !#zh
* 设置子网格索引。
* @method setIndices
- * @param {[Number]} indices - the sub mesh indices.
- * @param {Number} index - sub mesh index.
+ * @param {[Number]|Uint16Array|Uint8Array} indices - the sub mesh indices.
+ * @param {Number} [index] - sub mesh index.
+ * @param {Boolean} [dynamic] - whether or not to use dynamic buffer.
*/
- setIndices (indices, index) {
+ setIndices (indices, index, dynamic) {
index = index || 0;
- let data = new Uint16Array(indices);
-
- let ib = this._ibs[index];
- if (!ib) {
- let buffer = new gfx.IndexBuffer(
- renderer.device,
- gfx.INDEX_FMT_UINT16,
- gfx.USAGE_STATIC,
- data,
- data.length
- );
-
- this._ibs[index] = {
- buffer: buffer,
- data: data,
- dirty: false
- };
+ let iData = indices;
+ if (indices instanceof Uint16Array) {
+ iData = new Uint8Array(indices.buffer, indices.byteOffset, indices.byteLength);
+ }
+ else if (Array.isArray(indices)) {
+ iData = new Uint16Array(indices);
+ iData = new Uint8Array(iData.buffer, iData.byteOffset, iData.byteLength);
+ }
- let vb = this._vbs[0];
- this._subMeshes[index] = new renderEngine.InputAssembler(vb.buffer, buffer);
+ let usage = dynamic ? gfx.USAGE_DYNAMIC : gfx.USAGE_STATIC;
+
+ let subData = this._subDatas[index];
+ if (!subData.ib) {
+ subData.iData = iData;
+ if (!(CC_JSB && CC_NATIVERENDERER)) {
+ let buffer = new gfx.IndexBuffer(
+ renderer.device,
+ gfx.INDEX_FMT_UINT16,
+ usage,
+ iData,
+ iData.byteLength / gfx.IndexBuffer.BYTES_PER_INDEX[gfx.INDEX_FMT_UINT16]
+ );
+
+ subData.ib = buffer;
+ this._subMeshes[index]._indexBuffer = subData.ib;
+ }
}
else {
- ib.data = data;
- ib.dirty = true
+ subData.iData = iData;
+ subData.iDirty = true;
}
},
+ /**
+ * !#en
+ * Set the sub mesh primitive type.
+ * !#zh
+ * 设置子网格绘制线条的方式。
+ * @method setPrimitiveType
+ * @param {Number} type
+ * @param {Number} index
+ */
+ setPrimitiveType (type, index) {
+ index = index || 0;
+ let subMesh = this._subMeshes[index];
+ if (!subMesh) {
+ cc.warn(`Do not have sub mesh at index ${index}`);
+ return;
+ }
+ this._subMeshes[index]._primitiveType = type;
+ },
+
/**
* !#en
* Clear the buffer data.
@@ -216,17 +399,31 @@ var Mesh = cc.Class({
clear () {
this._subMeshes.length = 0;
- let ibs = this._ibs;
- for (let i = 0; i < ibs.length; i++) {
- ibs[i].buffer.destroy();
+ let subDatas = this._subDatas;
+ for (let i = 0, len = subDatas.length; i < len; i++) {
+ let vb = subDatas[i].vb;
+ if (vb) {
+ vb.destroy();
+ }
+
+ let ib = subDatas[i].ib;
+ if (ib) {
+ ib.destroy();
+ }
}
- ibs.length = 0;
+ subDatas.length = 0;
+ },
- let vbs = this._vbs;
- for (let i = 0; i < vbs.length; i++) {
- vbs[i].buffer.destroy();
- }
- vbs.length = 0;
+ /**
+ * !#en Set mesh bounding box
+ * !#zh 设置网格的包围盒
+ * @method setBoundingBox
+ * @param {Vec3} min
+ * @param {Vec3} max
+ */
+ setBoundingBox (min, max) {
+ this._minPos = min;
+ this._maxPos = max;
},
destroy () {
@@ -234,47 +431,141 @@ var Mesh = cc.Class({
},
_uploadData () {
- let vbs = this._vbs;
- for (let i = 0; i < vbs.length; i++) {
- let vb = vbs[i];
+ let subDatas = this._subDatas;
+ for (let i = 0, len = subDatas.length; i < len; i++) {
+ let subData = subDatas[i];
+
+ if (subData.vDirty) {
+ let buffer = subData.vb, data = subData.vData;
+ buffer.update(0, data);
+ subData.vDirty = false;
+ }
- if (vb.dirty) {
- vb.buffer.update(0, vb.data);
- vb.dirty = false;
+ if (subData.iDirty) {
+ let buffer = subData.ib, data = subData.iData;
+ buffer.update(0, data);
+ subData.iDirty = false;
}
}
+ },
+
+ _getAttrMeshData (subDataIndex, name) {
+ let subData = this._subDatas[subDataIndex];
+ if (!subData) return [];
+
+ let format = subData.vfm;
+ let fmt = format.element(name);
+ if (!fmt) return [];
+
+ if (!subData.attrDatas) {
+ subData.attrDatas = {};
+ }
+ let attrDatas = subData.attrDatas;
+ let data = attrDatas[name];
+ if (data) {
+ return data;
+ }
+ else {
+ data = attrDatas[name] = [];
+ }
- let ibs = this._ibs;
- for (let i = 0; i < ibs.length; i++) {
- let ib = ibs[i];
+ let vbData = subData.vData;
+ let dv = new DataView(vbData.buffer, vbData.byteOffset, vbData.byteLength);
- if (ib.dirty) {
- ib.buffer.update(0, ib.data);
- ib.dirty = false;
+ let stride = fmt.stride;
+ let eleOffset = fmt.offset;
+ let eleNum = fmt.num;
+ let eleByte = fmt.bytes / eleNum;
+ let fn = _compType2fn[fmt.type];
+ let vertexCount = vbData.byteLength / format._bytes;
+
+ for (let i = 0; i < vertexCount; i++) {
+ let offset = i * stride + eleOffset;
+ for (let j = 0; j < eleNum; j++) {
+ let v = dv[fn](offset + j * eleByte, littleEndian);
+ data.push(v);
}
}
- },
- _initWithModel (model) {
- if (!model) return;
- this._model = model;
- this._model.initMesh(this);
+ return data;
},
- _serialize: CC_EDITOR && function () {
- return {
- modelUuid: this._modelUuid,
- meshID: this._meshID,
+ /**
+ * !#en Read the specified attributes of the subgrid into the target buffer.
+ * !#zh 读取子网格的指定属性到目标缓冲区中。
+ * @param {Number} primitiveIndex The subgrid index.
+ * @param {String} attributeName attribute name.
+ * @param {ArrayBuffer} buffer The target buffer.
+ * @param {Number} stride The byte interval between adjacent attributes in the target buffer.
+ * @param {Number} offset The offset of the first attribute in the target buffer.
+ * @returns {Boolean} If the specified sub-grid does not exist, the sub-grid does not exist, or the specified attribute cannot be read, return `false`, otherwise return` true`.
+ * @method copyAttribute
+ */
+ copyAttribute (primitiveIndex, attributeName, buffer, stride, offset) {
+ let written = false;
+ let subData = this._subDatas[primitiveIndex];
+
+ if (!subData) return written;
+
+ let format = subData.vfm;
+ let fmt = format.element(attributeName);
+
+ if (!fmt) return written;
+
+ let writter = _compType2write[fmt.type];
+
+ if (!writter) return written;
+
+ let data = this._getAttrMeshData(primitiveIndex, attributeName);
+ let vertexCount = subData.vData.byteLength / format._bytes;
+ let eleByte = fmt.bytes / fmt.num;
+
+ if (data.length > 0) {
+ const outputView = new DataView(buffer, offset);
+
+ let outputStride = stride;
+ let num = fmt.num;
+
+ for (let i = 0; i < vertexCount; ++i) {
+ let index = i * num;
+ for (let j = 0; j < num; ++j) {
+ const inputOffset = index + j;
+ const outputOffset = outputStride * i + eleByte * j;
+
+ outputView[writter](outputOffset, data[inputOffset], littleEndian);
+ }
+ }
+
+ written = true;
}
+
+ return written;
},
- _deserialize (data, handle) {
- this._modelUuid = data.modelUuid;
- this._meshID = data.meshID;
+ /**
+ * !#en Read the index data of the subgrid into the target array.
+ * !#zh 读取子网格的索引数据到目标数组中。
+ * @param {Number} primitiveIndex The subgrid index.
+ * @param {TypedArray} outputArray The target array.
+ * @returns {Boolean} returns `false` if the specified sub-grid does not exist or the sub-grid does not have index data, otherwise returns` true`.
+ * @method copyIndices
+ */
+ copyIndices (primitiveIndex, outputArray) {
+ let subData = this._subDatas[primitiveIndex];
+
+ if (!subData) return false;
- if (this._modelUuid) {
- handle.result.push(this, '_modelSetter', this._modelUuid);
+ const iData = subData.iData;
+ const indexCount = iData.length / 2;
+
+ const dv = new DataView(iData.buffer, iData.byteOffset, iData.byteLength);
+ const fn = _compType2fn[gfx.INDEX_FMT_UINT8];
+
+ for (let i = 0; i < indexCount; ++i) {
+ outputArray[i] = dv[fn](i * 2);
}
+
+ return true;
}
});
diff --git a/cocos2d/core/mesh/CCMeshRenderer.js b/cocos2d/core/mesh/CCMeshRenderer.js
index be851063f72..e858fbba5dd 100644
--- a/cocos2d/core/mesh/CCMeshRenderer.js
+++ b/cocos2d/core/mesh/CCMeshRenderer.js
@@ -23,18 +23,80 @@
THE SOFTWARE.
****************************************************************************/
+import gfx from '../../renderer/gfx';
+import InputAssembler from '../../renderer/core/input-assembler';
+import Aabb from '../geom-utils/aabb';
+import Vec3 from '../value-types/vec3';
+import Mat4 from '../value-types/mat4';
+import MaterialVariant from '../assets/material/material-variant';
+
const RenderComponent = require('../components/CCRenderComponent');
const Mesh = require('./CCMesh');
-const renderEngine = require('../renderer/render-engine');
-const gfx = renderEngine.gfx;
const RenderFlow = require('../renderer/render-flow');
+const Renderer = require('../renderer');
+const Material = require('../assets/material/CCMaterial');
+
+
+/**
+ * !#en Shadow projection mode
+ *
+ * !#ch 阴影投射方式
+ * @static
+ * @enum MeshRenderer.ShadowCastingMode
+ */
+let ShadowCastingMode = cc.Enum({
+ /**
+ * !#en
+ *
+ * !#ch 关闭阴影投射
+ * @property OFF
+ * @readonly
+ * @type {Number}
+ */
+ OFF: 0,
+ /**
+ * !#en
+ *
+ * !#ch 开启阴影投射,当阴影光产生的时候
+ * @property ON
+ * @readonly
+ * @type {Number}
+ */
+ ON: 1,
+ // /**
+ // * !#en
+ // *
+ // * !#ch 可以从网格的任意一遍投射出阴影
+ // * @property TWO_SIDED
+ // * @readonly
+ // * @type {Number}
+ // */
+ // TWO_SIDED: 2,
+ // /**
+ // * !#en
+ // *
+ // * !#ch 只显示阴影
+ // * @property SHADOWS_ONLY
+ // * @readonly
+ // * @type {Number}
+ // */
+ // SHADOWS_ONLY: 3,
+});
+/**
+ * !#en
+ * Mesh Renderer Component
+ * !#zh
+ * 网格渲染组件
+ * @class MeshRenderer
+ * @extends RenderComponent
+ */
let MeshRenderer = cc.Class({
name: 'cc.MeshRenderer',
extends: RenderComponent,
editor: CC_EDITOR && {
- menu: 'i18n:MAIN_MENU.component.renderers/MeshRenderer',
+ menu: 'i18n:MAIN_MENU.component.mesh/MeshRenderer',
},
properties: {
@@ -43,78 +105,378 @@ let MeshRenderer = cc.Class({
type: Mesh
},
+ _receiveShadows: false,
+ _shadowCastingMode: ShadowCastingMode.OFF,
+
+ _enableAutoBatch: false,
+
+ /**
+ * !#en
+ * The mesh which the renderer uses.
+ * !#zh
+ * 设置使用的网格
+ * @property {Mesh} mesh
+ */
mesh: {
get () {
return this._mesh;
},
set (v) {
if (this._mesh === v) return;
- this._mesh = v;
- this.activeMaterials(true);
- this.markForUpdateRenderData(true);
+ this._setMesh(v);
+ if (!v) {
+ this.disableRender();
+ return;
+ }
+ this.markForRender(true);
this.node._renderFlag |= RenderFlow.FLAG_TRANSFORM;
},
- type: Mesh
+ type: Mesh,
+ animatable: false
},
textures: {
default: [],
- type: cc.Texture2D
- }
+ type: cc.Texture2D,
+ visible: false
+ },
+
+ /**
+ * !#en
+ * Whether the mesh should receive shadows.
+ * !#zh
+ * 网格是否接受光源投射的阴影
+ * @property {Boolean} receiveShadows
+ */
+ receiveShadows: {
+ get () {
+ return this._receiveShadows;
+ },
+ set (val) {
+ this._receiveShadows = val;
+ this._updateReceiveShadow();
+ },
+ animatable: false
+ },
+
+ /**
+ * !#en
+ * Shadow Casting Mode
+ * !#zh
+ * 网格投射阴影的模式
+ * @property {ShadowCastingMode} shadowCastingMode
+ */
+ shadowCastingMode: {
+ get () {
+ return this._shadowCastingMode;
+ },
+ set (val) {
+ this._shadowCastingMode = val;
+ this._updateCastShadow();
+ },
+ type: ShadowCastingMode,
+ animatable: false
+ },
+
+ /**
+ * !#en
+ * Enable auto merge mesh, only support when mesh's VertexFormat, PrimitiveType, materials are all the same
+ * !#zh
+ * 开启自动合并 mesh 功能,只有在网格的 顶点格式,PrimitiveType, 使用的材质 都一致的情况下才会有效
+ * @property {Boolean} enableAutoBatch
+ */
+ enableAutoBatch: {
+ get () {
+ return this._enableAutoBatch;
+ },
+ set (val) {
+ this._enableAutoBatch = val;
+ }
+ },
+ },
+
+ statics: {
+ ShadowCastingMode: ShadowCastingMode
},
ctor () {
- this._renderDatas = [];
- this._materials = [];
+ this._boundingBox = cc.geomUtils && new Aabb();
+
+ if (CC_DEBUG) {
+ this._debugDatas = {
+ wireFrame: [],
+ normal: []
+ };
+ }
},
onEnable () {
this._super();
- this.activeMaterials();
+ if (this._mesh && !this._mesh.loaded) {
+ this.disableRender();
+ this._mesh.once('load', () => {
+ if (!this.isValid) return;
+ this._setMesh(this._mesh);
+ this.markForRender(true);
+ });
+ cc.assetManager.postLoadNative(this._mesh);
+ }
+ else {
+ this._setMesh(this._mesh);
+ }
+
+ this._updateRenderNode();
+ this._updateMaterial();
},
- _createMaterial (subMesh) {
- let material = new renderEngine.MeshMaterial();
- material.color = cc.Color.WHITE;
- if (cc.macro.ENABLE_3D) {
- material._mainTech._passes[0].setDepth(true, true);
- }
- material.useModel = true;
+ onDestroy () {
+ this._setMesh(null);
+ cc.pool.assembler.put(this._assembler);
+ },
+
+ _updateRenderNode () {
+ this._assembler.setRenderNode(this.node);
+ },
- if (subMesh._vertexBuffer._format._attr2el[gfx.ATTR_COLOR]) {
- material.useAttributeColor = true;
+ _setMesh (mesh) {
+ if (cc.geomUtils && mesh) {
+ Aabb.fromPoints(this._boundingBox, mesh._minPos, mesh._maxPos);
}
- return material;
+ if (this._mesh) {
+ this._mesh.off('init-format', this._updateMeshAttribute, this);
+ }
+ if (mesh) {
+ mesh.on('init-format', this._updateMeshAttribute, this);
+ }
+ this._mesh = mesh;
+ this._assembler && (this._assembler._worldDatas = {});
+ this._updateMeshAttribute();
},
- _reset () {
- this._materials.length = 0;
- this._material = null;
+ _getDefaultMaterial () {
+ return Material.getBuiltinMaterial('unlit');
},
- activeMaterials (force) {
- if (!this._mesh || this._mesh.subMeshes.length === 0) {
- this.disableRender();
+ _validateRender () {
+ let mesh = this._mesh;
+ if (mesh && mesh._subDatas.length > 0) {
return;
}
- if (this._material && !force) {
- return;
+ this.disableRender();
+ },
+
+ _updateMaterial () {
+ // TODO: used to upgrade from 2.1, should be removed
+ let textures = this.textures;
+ if (textures && textures.length > 0) {
+ let defaultMaterial = this._getDefaultMaterial();
+ for (let i = 0; i < textures.length; i++) {
+ let material = this._materials[i];
+ if (material && material._uuid !== defaultMaterial._uuid) continue;
+ if (!material) {
+ material = MaterialVariant.create(defaultMaterial, this);
+ this.setMaterial(i, material);
+ }
+ material.setProperty('diffuseTexture', textures[i]);
+ }
}
-
- this._reset();
- let subMeshes = this._mesh._subMeshes;
- for (let i = 0; i < subMeshes.length; i++) {
- let material = this._createMaterial(subMeshes[i]);
- this._materials.push(material);
+ this._updateReceiveShadow();
+ this._updateCastShadow();
+ this._updateMeshAttribute();
+ },
+
+ _updateReceiveShadow () {
+ let materials = this.getMaterials();
+ for (let i = 0; i < materials.length; i++) {
+ materials[i].define('CC_USE_SHADOW_MAP', this._receiveShadows, undefined, true);
+ }
+ },
+
+ _updateCastShadow () {
+ let materials = this.getMaterials();
+ for (let i = 0; i < materials.length; i++) {
+ materials[i].define('CC_CASTING_SHADOW', this._shadowCastingMode === ShadowCastingMode.ON, undefined, true);
}
- this._material = this._materials[0];
-
- this.markForUpdateRenderData(true);
- this.markForRender(true);
- }
+ },
+
+ _updateMeshAttribute () {
+ let subDatas = this._mesh && this._mesh.subDatas;
+ if (!subDatas) return;
+
+ let materials = this.getMaterials();
+ for (let i = 0; i < materials.length; i++) {
+ if (!subDatas[i]) break;
+ let vfm = subDatas[i].vfm;
+ let material = materials[i];
+ material.define('CC_USE_ATTRIBUTE_COLOR', !!vfm.element(gfx.ATTR_COLOR), undefined, true);
+ material.define('CC_USE_ATTRIBUTE_UV0', !!vfm.element(gfx.ATTR_UV0), undefined, true);
+ material.define('CC_USE_ATTRIBUTE_NORMAL', !!vfm.element(gfx.ATTR_NORMAL), undefined, true);
+ material.define('CC_USE_ATTRIBUTE_TANGENT', !!vfm.element(gfx.ATTR_TANGENT), undefined, true);
+ }
+
+ if (CC_DEBUG) {
+ for (let name in this._debugDatas) {
+ this._debugDatas[name].length = 0;
+ }
+ }
+
+ if (CC_JSB && CC_NATIVERENDERER) {
+ this._assembler.updateMeshData(this);
+ }
+ },
+
+ _checkBacth () {
+ },
});
+if (CC_DEBUG) {
+ const BLACK_COLOR = cc.Color.BLACK;
+ const RED_COLOR = cc.Color.RED;
+
+ let v3_tmp = [cc.v3(), cc.v3()];
+ let mat4_tmp = cc.mat4();
+
+ let createDebugDataFns = {
+ normal (comp, ia, subData, subIndex) {
+ let oldVfm = subData.vfm;
+
+ let normalEle = oldVfm.element(gfx.ATTR_NORMAL);
+ let posEle = oldVfm.element(gfx.ATTR_POSITION);
+ let jointEle = oldVfm.element(gfx.ATTR_JOINTS);
+ let weightEle = oldVfm.element(gfx.ATTR_WEIGHTS);
+
+ if (!normalEle || !posEle) {
+ return;
+ }
+
+ let indices = [];
+ let vbData = [];
+
+ let lineLength = 100;
+ Vec3.set(v3_tmp[0], 5, 0, 0);
+ Mat4.invert(mat4_tmp, comp.node._worldMatrix);
+ Vec3.transformMat4Normal(v3_tmp[0], v3_tmp[0], mat4_tmp);
+ lineLength = v3_tmp[0].mag();
+
+ let mesh = comp.mesh;
+ let posData = mesh._getAttrMeshData(subIndex, gfx.ATTR_POSITION);
+ let normalData = mesh._getAttrMeshData(subIndex, gfx.ATTR_NORMAL);
+ let jointData = mesh._getAttrMeshData(subIndex, gfx.ATTR_JOINTS);
+ let weightData = mesh._getAttrMeshData(subIndex, gfx.ATTR_WEIGHTS);
+
+ let vertexCount = posData.length / posEle.num;
+
+ for (let i = 0; i < vertexCount; i++) {
+ let normalIndex = i * normalEle.num;
+ let posIndex = i * posEle.num;
+
+ Vec3.set(v3_tmp[0], normalData[normalIndex], normalData[normalIndex+1], normalData[normalIndex+2]);
+ Vec3.set(v3_tmp[1], posData[posIndex], posData[posIndex+1], posData[posIndex+2]);
+ Vec3.scaleAndAdd(v3_tmp[0], v3_tmp[1], v3_tmp[0], lineLength);
+
+ for (let lineIndex = 0; lineIndex < 2; lineIndex++) {
+ vbData.push(v3_tmp[lineIndex].x, v3_tmp[lineIndex].y, v3_tmp[lineIndex].z);
+ if (jointEle) {
+ let jointIndex = i * jointEle.num;
+ for (let j = 0; j < jointEle.num; j++) {
+ vbData.push(jointData[jointIndex + j]);
+ }
+ }
+ if (weightEle) {
+ let weightIndex = i * weightEle.num;
+ for (let j = 0; j < weightEle.num; j++) {
+ vbData.push(weightData[weightIndex + j]);
+ }
+ }
+ }
+
+ indices.push(i*2, i*2+1);
+ }
+
+ let formatOpts = [
+ { name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 3 },
+ ];
+ if (jointEle) {
+ formatOpts.push({ name: gfx.ATTR_JOINTS, type: gfx.ATTR_TYPE_FLOAT32, num: jointEle.num })
+ }
+ if (weightEle) {
+ formatOpts.push({ name: gfx.ATTR_WEIGHTS, type: gfx.ATTR_TYPE_FLOAT32, num: weightEle.num })
+ }
+ let gfxVFmt = new gfx.VertexFormat(formatOpts);
+
+ let vb = new gfx.VertexBuffer(
+ Renderer.device,
+ gfxVFmt,
+ gfx.USAGE_STATIC,
+ new Float32Array(vbData)
+ );
+
+ let ibData = new Uint16Array(indices);
+ let ib = new gfx.IndexBuffer(
+ Renderer.device,
+ gfx.INDEX_FMT_UINT16,
+ gfx.USAGE_STATIC,
+ ibData,
+ ibData.length
+ );
+
+ let m = MaterialVariant.createWithBuiltin('unlit');
+ m.setProperty('diffuseColor', RED_COLOR);
+
+ return {
+ material: m,
+ ia: new InputAssembler(vb, ib, gfx.PT_LINES)
+ };
+ },
+
+ wireFrame (comp, ia, subData) {
+ let oldIbData = subData.getIData(Uint16Array);
+ let m = MaterialVariant.createWithBuiltin('unlit');
+ m.setProperty('diffuseColor', BLACK_COLOR);
+
+ let indices = [];
+ for (let i = 0; i < oldIbData.length; i+=3) {
+ let a = oldIbData[ i + 0 ];
+ let b = oldIbData[ i + 1 ];
+ let c = oldIbData[ i + 2 ];
+ indices.push(a, b, b, c, c, a);
+ }
+
+ let ibData = new Uint16Array(indices);
+ let ib = new gfx.IndexBuffer(
+ Renderer.device,
+ gfx.INDEX_FMT_UINT16,
+ gfx.USAGE_STATIC,
+ ibData,
+ ibData.length
+ );
+
+ return {
+ material: m,
+ ia: new InputAssembler(ia._vertexBuffer, ib, gfx.PT_LINES)
+ };
+ }
+ };
+
+ let _proto = MeshRenderer.prototype;
+ _proto._updateDebugDatas = function () {
+ let debugDatas = this._debugDatas;
+ let subMeshes = this._mesh.subMeshes;
+ let subDatas = this._mesh._subDatas;
+ for (let name in debugDatas) {
+ let debugData = debugDatas[name];
+ if (debugData.length === subMeshes.length) continue;
+ if (!cc.macro['SHOW_MESH_' + name.toUpperCase()]) continue;
+
+ debugData.length = subMeshes.length;
+ for (let i = 0; i < subMeshes.length; i++) {
+ debugData[i] = createDebugDataFns[name](this, subMeshes[i], subDatas[i], i);
+ }
+ }
+ };
+}
+
cc.MeshRenderer = module.exports = MeshRenderer;
diff --git a/cocos2d/core/mesh/index.js b/cocos2d/core/mesh/index.js
index 55de77b9ed4..5ba5fb7ad84 100644
--- a/cocos2d/core/mesh/index.js
+++ b/cocos2d/core/mesh/index.js
@@ -1,3 +1,5 @@
require('./CCMesh');
-require('./CCMeshRenderer');
-require('./mesh-renderer');
+if (!CC_EDITOR || !Editor.isMainProcess) {
+ require('./CCMeshRenderer');
+ require('./mesh-renderer');
+}
diff --git a/cocos2d/core/mesh/mesh-data.js b/cocos2d/core/mesh/mesh-data.js
new file mode 100644
index 00000000000..c21b8d8b0a9
--- /dev/null
+++ b/cocos2d/core/mesh/mesh-data.js
@@ -0,0 +1,179 @@
+/****************************************************************************
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ http://www.cocos.com
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import gfx from '../../renderer/gfx';
+
+/**
+ * The class BufferRange denotes a range of the buffer.
+ * @class BufferRange
+ */
+export let BufferRange = cc.Class({
+ name: 'cc.BufferRange',
+
+ properties: {
+ /**
+ * The offset of the range.
+ * @property {Number} offset
+ */
+ offset: 0,
+ /**
+ * The length of the range.
+ * @property {Number} length
+ */
+ length: 0
+ }
+});
+
+/**
+ * @class VertexFormat
+ */
+export let VertexFormat = cc.Class({
+ name: 'cc.mesh.VertexFormat',
+
+ properties: {
+ name: '',
+ type: -1,
+ num: -1,
+ normalize: false
+ }
+});
+
+/**
+ * A vertex bundle describes a serials of vertex attributes.
+ * These vertex attributes occupy a range of the buffer and
+ * are interleaved, no padding bytes, in the range.
+ */
+export let VertexBundle = cc.Class({
+ name: 'cc.mesh.VertexBundle',
+ properties: {
+ /**
+ * The data range of this bundle.
+ * This range of data is essentially mapped to a GPU vertex buffer.
+ * @property {BufferRange} data
+ */
+ data: {
+ default: null,
+ type: BufferRange
+ },
+ /**
+ * The attribute formats.
+ * @property {VertexFormat} formats
+ */
+ formats: {
+ default: [],
+ type: VertexFormat
+ },
+ /**
+ * The bundle's vertices count.
+ */
+ verticesCount: 0,
+ }
+});
+
+/**
+ * A primitive is a geometry constituted with a list of
+ * same topology primitive graphic(such as points, lines or triangles).
+ */
+export let Primitive = cc.Class({
+ name: 'cc.mesh.Primitive',
+ properties: {
+ /**
+ * The vertex bundle that the primitive use.
+ * @property {[Number]} vertexBundleIndices
+ */
+ vertexBundleIndices: {
+ default: [],
+ type: cc.Float
+ },
+ /**
+ * The data range of the primitive.
+ * This range of data is essentially mapped to a GPU indices buffer.
+ * @property {BufferRange} data
+ */
+ data: {
+ default: null,
+ type: BufferRange
+ },
+ /**
+ * The type of this primitive's indices.
+ * @property {Number} indexUnit
+ */
+ indexUnit: gfx.INDEX_FMT_UINT16,
+ /**
+ * The primitive's topology.
+ * @property {Number} topology
+ */
+ topology: gfx.PT_TRIANGLES
+ }
+});
+
+export function MeshData () {
+ this.vData = null; // Uint8Array;
+ this.float32VData = null;
+ this.uint32VData = null;
+ this.iData = null; // Uint8Array;
+ this.uint16IData = null;
+ this.vfm = null;
+ this.offset = 0;
+
+ this.vb = null;
+ this.ib = null;
+ this.vDirty = false;
+ this.iDirty = false;
+
+ this.enable = true;
+}
+
+MeshData.prototype.setVData = function (data) {
+ this.vData = data;
+ this.float32VData = null;
+ this.uint32VData = null;
+}
+
+MeshData.prototype.getVData = function (format) {
+ if (format === Float32Array) {
+ if (!this.float32VData) {
+ this.float32VData = new Float32Array(this.vData.buffer, this.vData.byteOffset, this.vData.byteLength / 4);
+ }
+ return this.float32VData;
+ }
+ else if (format === Uint32Array) {
+ if (!this.uint32VData) {
+ this.uint32VData = new Uint32Array(this.vData.buffer, this.vData.byteOffset, this.vData.byteLength / 4);
+ }
+ return this.uint32VData;
+ }
+ return this.vData;
+}
+
+MeshData.prototype.getIData = function (format) {
+ if (format === Uint16Array) {
+ if (!this.uint16IData) {
+ this.uint16IData = new Uint16Array(this.iData.buffer, this.iData.byteOffset, this.iData.byteLength / 2);
+ }
+ return this.uint16IData;
+ }
+ return this.iData;
+}
diff --git a/cocos2d/core/mesh/mesh-renderer.js b/cocos2d/core/mesh/mesh-renderer.js
index 508ce148de0..483af9a2c7a 100644
--- a/cocos2d/core/mesh/mesh-renderer.js
+++ b/cocos2d/core/mesh/mesh-renderer.js
@@ -23,107 +23,159 @@
THE SOFTWARE.
****************************************************************************/
+import Assembler from '../renderer/assembler';
+import gfx from '../../renderer/gfx';
+import Vec3 from '../value-types/vec3';
+
const MeshRenderer = require('./CCMeshRenderer');
-const renderEngine = require('../renderer/render-engine');
-const IARenderData = renderEngine.IARenderData;
-const gfx = renderEngine.gfx;
-const InputAssembler = renderEngine.InputAssembler;
+let _tmp_vec3 = new Vec3();
-const BLACK_COLOR = cc.Color.BLACK;
+export default class MeshRendererAssembler extends Assembler {
+ init (renderComp) {
+ super.init(renderComp);
+
+ this._worldDatas = {};
+ this._renderNode = null;
+ }
-let meshRendererAssembler = {
- useModel: true,
- updateRenderData (comp) {
- let renderDatas = comp._renderDatas;
- renderDatas.length = 0;
+ setRenderNode (node) {
+ this._renderNode = node;
+ }
+
+ fillBuffers (comp, renderer) {
if (!comp.mesh) return;
+
+ comp.mesh._uploadData();
+
+ // update culling mask
+ let isCullingMaskSame = renderer.cullingMask === comp.node._cullingMask;
+
+ let enableAutoBatch = comp.enableAutoBatch;
+
+ let materials = comp._materials;
let submeshes = comp.mesh._subMeshes;
+ let subDatas = comp.mesh.subDatas;
for (let i = 0; i < submeshes.length; i++) {
- let data = new IARenderData();
- data.material = comp._materials[i];
- data.ia = submeshes[i];
- renderDatas.push(data);
- }
- },
-
- createWireFrameData (ia, oldIbData, material, renderer) {
- let data = new IARenderData();
- let m = material.clone();
- m.color = BLACK_COLOR;
- m.useTexture = false;
- if (cc.macro.ENABLE_3D) {
- m._mainTech._passes[0].setDepth(true, true);
- }
- data.material = m;
-
- let indices = [];
- for (let i = 0; i < oldIbData.length; i+=3) {
- let a = oldIbData[ i + 0 ];
- let b = oldIbData[ i + 1 ];
- let c = oldIbData[ i + 2 ];
- indices.push(a, b, b, c, c, a);
- }
+ let ia = submeshes[i];
+ let meshData = subDatas[i];
- let ibData = new Uint16Array(indices);
- let ib = new gfx.IndexBuffer(
- renderer._device,
- gfx.INDEX_FMT_UINT16,
- gfx.USAGE_STATIC,
- ibData,
- ibData.length
- );
+ let material = materials[i] || materials[0];
- data.ia = new renderEngine.InputAssembler(ia._vertexBuffer, ib, gfx.PT_LINES);
- return data;
- },
+ if (!enableAutoBatch || !meshData.canBatch || ia._primitiveType !== gfx.PT_TRIANGLES) {
+ renderer._flush();
- fillBuffers (comp, renderer) {
- if (!comp.mesh) return;
+ renderer.material = material;
+ renderer.cullingMask = comp.node._cullingMask;
+ renderer.node = this._renderNode;
- renderer._flush();
+ renderer._flushIA(ia);
- let renderDatas = comp._renderDatas;
- let submeshes = comp.mesh._subMeshes;
- if (cc.macro.SHOW_MESH_WIREFRAME) {
- if (renderDatas.length === submeshes.length) {
- let ibs = comp.mesh._ibs;
- for (let i = 0; i < submeshes.length; i++) {
- let data = renderDatas[i];
- renderDatas.push( this.createWireFrameData(data.ia, ibs[i].data, data.material, renderer) );
- }
+ continue;
}
- }
- else {
- renderDatas.length = submeshes.length;
- }
- let tmpMaterial = renderer.material;
+ if (!isCullingMaskSame ||
+ material.getHash() !== renderer.material.getHash()) {
+ renderer._flush();
+ }
- let tmpNode = renderer.node;
- renderer.node = comp._material.useModel ? comp.node : renderer._dummyNode;
+ renderer.material = material;
+ renderer.cullingMask = comp.node._cullingMask;
+ renderer.node = renderer._dummyNode;
+
+ this._fillBuffer(comp, meshData, renderer, i);
+ }
- let textures = comp.textures;
- let materials = comp._materials;
- for (let i = 0; i < renderDatas.length; i++) {
- let renderData = renderDatas[i];
- let material = renderData.material;
- if (textures[i]) {
- material.texture = textures[i];
+ if (CC_DEBUG &&
+ (cc.macro.SHOW_MESH_WIREFRAME || cc.macro.SHOW_MESH_NORMAL) &&
+ !(comp.node._cullingMask & (1<> 2,
+ vertexId = offsetInfo.vertexOffset,
+ vbuf = buffer._vData,
+ ibuf = buffer._iData;
+
+ if (renderer.worldMatDirty || !this._worldDatas[dataIndex]) {
+ this._updateWorldVertices(dataIndex, vertexCount, vData, vtxFormat, comp.node._worldMatrix);
}
- comp.mesh._uploadData();
+ vbuf.set(this._worldDatas[dataIndex], vertexOffset);
+
+ for (let i = 0; i < indicesCount; i++) {
+ ibuf[indiceOffset + i] = vertexId + indices[i];
+ }
+ }
+
+ _updateWorldVertices (dataIndex, vertexCount, local, vtxFormat, wolrdMatrix) {
+ let world = this._worldDatas[dataIndex];
+ if (!world) {
+ world = this._worldDatas[dataIndex] = new Float32Array(local.length);
+ world.set(local);
+ }
+
+ let floatCount = vtxFormat._bytes / 4;
+
+ let elements = vtxFormat._elements;
+ for (let i = 0, n = elements.length; i < n; i++) {
+ let element = elements[i];
+ let attrOffset = element.offset / 4;
+
+ if (element.name === gfx.ATTR_POSITION || element.name === gfx.ATTR_NORMAL) {
+ let transformMat4 = element.name === gfx.ATTR_NORMAL ? Vec3.transformMat4Normal : Vec3.transformMat4;
+ for (let j = 0; j < vertexCount; j++) {
+ let offset = j * floatCount + attrOffset;
+
+ _tmp_vec3.x = local[offset];
+ _tmp_vec3.y = local[offset + 1];
+ _tmp_vec3.z = local[offset + 2];
+
+ transformMat4(_tmp_vec3, _tmp_vec3, wolrdMatrix);
+
+ world[offset] = _tmp_vec3.x;
+ world[offset + 1] = _tmp_vec3.y;
+ world[offset + 2] = _tmp_vec3.z;
+ }
+ }
+ }
+ }
- renderer.node = tmpNode;
- renderer.material = tmpMaterial;
+ _drawDebugDatas (comp, renderer, name) {
+ let debugDatas = comp._debugDatas[name];
+ if (!debugDatas) return;
+ for (let i = 0; i < debugDatas.length; i++) {
+ let debugData = debugDatas[i];
+ if (!debugData) continue;
+ let material = debugData.material;
+ renderer.material = material;
+ renderer._flushIA(debugData.ia);
+ }
}
-};
+}
-module.exports = MeshRenderer._assembler = meshRendererAssembler;
+Assembler.register(MeshRenderer, MeshRendererAssembler);
diff --git a/cocos2d/core/node-activator.js b/cocos2d/core/node-activator.js
index 992f3fdfb5b..a1d29ab40bb 100644
--- a/cocos2d/core/node-activator.js
+++ b/cocos2d/core/node-activator.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -37,19 +37,20 @@ var IsOnLoadCalled = Flags.IsOnLoadCalled;
var Deactivating = Flags.Deactivating;
var callPreloadInTryCatch = CC_EDITOR && callerFunctor('__preload');
-var callOnLoadInTryCatch = CC_EDITOR && callerFunctor('onLoad', null,
- 'target._objFlags |= ' + IsOnLoadCalled + '; arg(target);', _onLoadInEditor);
+var callOnLoadInTryCatch = CC_EDITOR && function (c) {
+ try {
+ c.onLoad();
+ }
+ catch (e) {
+ cc._throw(e);
+ }
+ c._objFlags |= IsOnLoadCalled;
+ _onLoadInEditor(c);
+};
var callOnDestroyInTryCatch = CC_EDITOR && callerFunctor('onDestroy');
-var callResetInTryCatch = CC_EDITOR && callerFunctor('resetInEditor');
var callOnFocusInTryCatch = CC_EDITOR && callerFunctor('onFocusInEditor');
var callOnLostFocusInTryCatch = CC_EDITOR && callerFunctor('onLostFocusInEditor');
-var callPreload = CC_SUPPORT_JIT ? 'c.__preload();' : function (c) { c.__preload(); };
-var callOnLoad = CC_SUPPORT_JIT ? ('c.onLoad();c._objFlags|=' + IsOnLoadCalled) : function (c) {
- c.onLoad();
- c._objFlags |= IsOnLoadCalled;
-};
-
// for __preload: use internally, no sort
var UnsortedInvoker = cc.Class({
extends: CompScheduler.LifeCycleInvoker,
@@ -68,12 +69,32 @@ var UnsortedInvoker = cc.Class({
},
});
-var invokePreload = CompScheduler.createInvokeImpl(
- CC_EDITOR ? callPreloadInTryCatch : callPreload
-);
-var invokeOnLoad = CompScheduler.createInvokeImpl(
- CC_EDITOR ? callOnLoadInTryCatch : callOnLoad
-);
+var invokePreload = CC_SUPPORT_JIT ?
+ CompScheduler.createInvokeImpl('c.__preload();') :
+ CompScheduler.createInvokeImpl(function (c) { c.__preload(); }, false, undefined, function (iterator) {
+ var array = iterator.array;
+ for (iterator.i = 0; iterator.i < array.length; ++iterator.i) {
+ array[iterator.i].__preload();
+ }
+ });
+var invokeOnLoad = CC_SUPPORT_JIT ?
+ CompScheduler.createInvokeImpl('c.onLoad();c._objFlags|=' + IsOnLoadCalled, false, IsOnLoadCalled) :
+ CompScheduler.createInvokeImpl(function (c) {
+ c.onLoad();
+ c._objFlags |= IsOnLoadCalled;
+ },
+ false,
+ IsOnLoadCalled,
+ function (iterator) {
+ var array = iterator.array;
+ for (iterator.i = 0; iterator.i < array.length; ++iterator.i) {
+ let comp = array[iterator.i];
+ comp.onLoad();
+ comp._objFlags |= IsOnLoadCalled;
+ }
+ }
+ );
+
var activateTasksPool = new js.Pool(MAX_POOL_SIZE);
activateTasksPool.get = function getActivateTask () {
@@ -165,14 +186,17 @@ var NodeActivator = cc.Class({
--originCount;
}
}
+
+ node._childArrivalOrder = node._children.length;
+
// activate children recursively
for (let i = 0, len = node._children.length; i < len; ++i) {
let child = node._children[i];
+ child._localZOrder = (child._localZOrder & 0xffff0000) | (i + 1);
if (child._active) {
this._activateNodeRecursively(child, preloadInvoker, onLoadInvoker, onEnableInvoker);
}
}
-
node._onPostActivated(true);
},
@@ -247,6 +271,10 @@ var NodeActivator = cc.Class({
},
activateComp: CC_EDITOR ? function (comp, preloadInvoker, onLoadInvoker, onEnableInvoker) {
+ if (!cc.isValid(comp, true)) {
+ // destroyed before activating
+ return;
+ }
if (cc.engine._isPlaying || comp.constructor._executeInEditMode) {
if (!(comp._objFlags & IsPreloadStarted)) {
comp._objFlags |= IsPreloadStarted;
@@ -283,6 +311,10 @@ var NodeActivator = cc.Class({
cc.director._compScheduler.enableComp(comp, onEnableInvoker);
}
} : function (comp, preloadInvoker, onLoadInvoker, onEnableInvoker) {
+ if (!cc.isValid(comp, true)) {
+ // destroyed before activating
+ return;
+ }
if (!(comp._objFlags & IsPreloadStarted)) {
comp._objFlags |= IsPreloadStarted;
if (comp.__preload) {
@@ -325,6 +357,7 @@ var NodeActivator = cc.Class({
if (comp.onDestroy && (comp._objFlags & IsOnLoadCalled)) {
if (cc.engine._isPlaying || comp.constructor._executeInEditMode) {
callOnDestroyInTryCatch(comp);
+ comp._objFlags &= ~IsOnLoadCalled; // In case call onDestroy twice in undo operation
}
}
} : function (comp) {
@@ -336,9 +369,14 @@ var NodeActivator = cc.Class({
}
},
- resetComp: CC_EDITOR && function (comp) {
+ resetComp: CC_EDITOR && function (comp, didResetToDefault) {
if (comp.resetInEditor) {
- callResetInTryCatch(comp);
+ try {
+ comp.resetInEditor(didResetToDefault);
+ }
+ catch (e) {
+ cc._throw(e);
+ }
}
}
});
diff --git a/cocos2d/core/physics/CCPhysicsContact.js b/cocos2d/core/physics/CCPhysicsContact.js
index a1aaf593772..89354157ba6 100644
--- a/cocos2d/core/physics/CCPhysicsContact.js
+++ b/cocos2d/core/physics/CCPhysicsContact.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -418,9 +418,17 @@ PhysicsContact.put = function (b2contact) {
var _p = PhysicsContact.prototype;
/**
+ * !#en
+ * One of the collider that collided
+ * !#zh
+ * 发生碰撞的碰撞体之一
* @property {Collider} colliderA
*/
/**
+ * !#en
+ * One of the collider that collided
+ * !#zh
+ * 发生碰撞的碰撞体之一
* @property {Collider} colliderB
*/
/**
diff --git a/cocos2d/core/physics/CCPhysicsManager.js b/cocos2d/core/physics/CCPhysicsManager.js
index e13ff732ffa..81ae0c5f652 100644
--- a/cocos2d/core/physics/CCPhysicsManager.js
+++ b/cocos2d/core/physics/CCPhysicsManager.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -53,7 +53,8 @@ var vec2_tmp = cc.v2();
* 物理系统将 box2d 作为内部物理系统,并且隐藏了大部分 box2d 实现细节(比如创建刚体,同步刚体信息到节点中等)。
* 你可以通过物理系统访问一些 box2d 常用的功能,比如点击测试,射线测试,设置测试信息等。
* 物理系统还管理碰撞信息的分发,她会在产生碰撞时,将碰撞信息分发到各个碰撞回调中。
- * 注意:你需要先在刚体中开启碰撞接听才会产生相应的碰撞回调。
+ * 注意:你需要先在刚体中开启碰撞接听才会产生相应的碰撞回调。
+ * 支持的物理系统指定绘制信息事件,请参阅 {{#crossLink "PhysicsManager.DrawBits"}}{{/crossLink}}
* @class PhysicsManager
* @uses EventTarget
*/
@@ -61,22 +62,6 @@ var PhysicsManager = cc.Class({
mixins: [cc.EventTarget],
statics: {
- /**
- * !#en
- * The draw bits for drawing physics debug information.
- * !#zh
- * 指定物理系统需要绘制哪些调试信息。
- * @property {DrawBits} DrawBits
- * @static
- * @example
- *
- * cc.director.getPhysicsManager().debugDrawFlags =
- // cc.PhysicsManager.DrawBits.e_aabbBit |
- // cc.PhysicsManager.DrawBits.e_pairBit |
- // cc.PhysicsManager.DrawBits.e_centerOfMassBit |
- cc.PhysicsManager.DrawBits.e_jointBit |
- cc.PhysicsManager.DrawBits.e_shapeBit;
- */
DrawBits: DrawBits,
/**
@@ -484,7 +469,7 @@ var PhysicsManager = cc.Class({
node.position = vec2_tmp;
// sync rotation
- node.rotation = angle;
+ node.angle = -angle;
node._eventMask = tempMask;
@@ -646,14 +631,40 @@ cc.js.getset(PhysicsManager.prototype, 'gravity',
cc.PhysicsManager = module.exports = PhysicsManager;
/**
- * @enum DrawBits
+ * !#en
+ * The draw bits for drawing physics debug information.
+ * example:
+ * ```js
+ * cc.director.getPhysicsManager().debugDrawFlags =
+ * // cc.PhysicsManager.DrawBits.e_aabbBit |
+ * // cc.PhysicsManager.DrawBits.e_pairBit |
+ * // cc.PhysicsManager.DrawBits.e_centerOfMassBit |
+ * cc.PhysicsManager.DrawBits.e_jointBit |
+ * cc.PhysicsManager.DrawBits.e_shapeBit;
+ * ```
+ * !#zh
+ * 指定物理系统需要绘制哪些调试信息。
+ * example:
+ * ```js
+ * cc.director.getPhysicsManager().debugDrawFlags =
+ * // cc.PhysicsManager.DrawBits.e_aabbBit |
+ * // cc.PhysicsManager.DrawBits.e_pairBit |
+ * // cc.PhysicsManager.DrawBits.e_centerOfMassBit |
+ * cc.PhysicsManager.DrawBits.e_jointBit |
+ * cc.PhysicsManager.DrawBits.e_shapeBit;
+ * ```
+ * @enum PhysicsManager.DrawBits
+ * @static
+
*/
+
/**
* !#en
* Draw bounding boxes
* !#zh
* 绘制包围盒
* @property {Number} e_aabbBit
+ * @static
*/
/**
* !#en
@@ -661,6 +672,7 @@ cc.PhysicsManager = module.exports = PhysicsManager;
* !#zh
* 绘制关节链接信息
* @property {Number} e_jointBit
+ * @static
*/
/**
* !#en
@@ -668,6 +680,7 @@ cc.PhysicsManager = module.exports = PhysicsManager;
* !#zh
* 绘制形状
* @property {Number} e_shapeBit
+ * @static
*/
/**
diff --git a/cocos2d/core/physics/CCPhysicsTypes.js b/cocos2d/core/physics/CCPhysicsTypes.js
index 0090e997074..2e5592af59a 100644
--- a/cocos2d/core/physics/CCPhysicsTypes.js
+++ b/cocos2d/core/physics/CCPhysicsTypes.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/physics/CCPolygonSeparator.js b/cocos2d/core/physics/CCPolygonSeparator.js
index 4b5aae73454..036f7c8de9d 100644
--- a/cocos2d/core/physics/CCPolygonSeparator.js
+++ b/cocos2d/core/physics/CCPolygonSeparator.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/physics/CCRigidBody.js b/cocos2d/core/physics/CCRigidBody.js
index da71792b99e..3c0e3f8c134 100644
--- a/cocos2d/core/physics/CCRigidBody.js
+++ b/cocos2d/core/physics/CCRigidBody.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -365,13 +365,14 @@ var RigidBody = cc.Class({
/**
* !#en
- * Is this body initially awake or sleeping?
+ * Set the sleep state of the body. A sleeping body has very low CPU cost.(When the rigid body is hit, if the rigid body is in sleep state, it will be immediately awakened.)
* !#zh
- * 是否立刻唤醒此刚体
+ * 设置刚体的睡眠状态。 睡眠的刚体具有非常低的 CPU 成本。(当刚体被碰撞到时,如果刚体处于睡眠状态,它会立即被唤醒)
* @property {Boolean} awake
* @default false
*/
awake: {
+ visible: false,
tooltip: CC_DEV && 'i18n:COMPONENT.physics.rigidbody.awake',
get: function () {
return this._b2Body ? this._b2Body.IsAwake() : false;
@@ -383,6 +384,20 @@ var RigidBody = cc.Class({
}
},
+ /**
+ * !#en
+ * Whether to wake up this rigid body during initialization
+ * !#zh
+ * 是否在初始化时唤醒此刚体
+ * @property {Boolean} awakeOnLoad
+ * @default true
+ */
+ awakeOnLoad: {
+ default: true,
+ tooltip: CC_DEV && 'i18n:COMPONENT.physics.rigidbody.awakeOnLoad',
+ animatable: false,
+ },
+
/**
* !#en
* Set the active state of the body. An inactive body is not
@@ -418,7 +433,7 @@ var RigidBody = cc.Class({
/**
* !#en
- * Gets a local point relative to the body's origin given a world point.
+ * Converts a given point in the world coordinate system to this rigid body's local coordinate system
* !#zh
* 将一个给定的世界坐标系下的点转换为刚体本地坐标系下的点
* @method getLocalPoint
@@ -439,7 +454,7 @@ var RigidBody = cc.Class({
/**
* !#en
- * Get the world coordinates of a point given the local coordinates.
+ * Converts a given point in this rigid body's local coordinate system to the world coordinate system
* !#zh
* 将一个给定的刚体本地坐标系下的点转换为世界坐标系下的点
* @method getWorldPoint
@@ -460,9 +475,9 @@ var RigidBody = cc.Class({
/**
* !#en
- * Get the world coordinates of a vector given the local coordinates.
+ * Converts a given vector in this rigid body's local coordinate system to the world coordinate system
* !#zh
- * 将一个给定的世界坐标系下的向量转换为刚体本地坐标系下的向量
+ * 将一个给定的刚体本地坐标系下的向量转换为世界坐标系下的向量
* @method getWorldVector
* @param {Vec2} localVector - a vector in world coordinates.
* @param {Vec2} out - optional, the receiving vector
@@ -481,9 +496,9 @@ var RigidBody = cc.Class({
/**
* !#en
- * Gets a local vector relative to the body's origin given a world vector.
+ * Converts a given vector in the world coordinate system to this rigid body's local coordinate system
* !#zh
- * 将一个给定的世界坐标系下的点转换为刚体本地坐标系下的点
+ * 将一个给定的世界坐标系下的向量转换为刚体本地坐标系下的向量
* @method getLocalVector
* @param {Vec2} worldVector - a vector in world coordinates.
* @param {Vec2} out - optional, the receiving vector
@@ -895,6 +910,8 @@ var RigidBody = cc.Class({
bodyDef.position = new b2.Vec2(pos.x / PTM_RATIO, pos.y / PTM_RATIO);
bodyDef.angle = -(Math.PI / 180) * getWorldRotation(node);
+ bodyDef.awake = this.awakeOnLoad;
+
cc.director.getPhysicsManager()._addBody(this, bodyDef);
this._inited = true;
diff --git a/cocos2d/core/physics/box2d-adapter.js b/cocos2d/core/physics/box2d-adapter.js
index 5c49b334383..84f7eae726c 100644
--- a/cocos2d/core/physics/box2d-adapter.js
+++ b/cocos2d/core/physics/box2d-adapter.js
@@ -1,10 +1,6 @@
let box2d = require('../../../external/box2d/box2d');
window.b2 = {};
-if (CC_QQPLAY) {
- // can only define global variable in this way
- b2 = window.b2;
-}
for (var key in box2d) {
if (key.indexOf('b2_') !== -1) {
diff --git a/cocos2d/core/physics/collider/CCPhysicsBoxCollider.js b/cocos2d/core/physics/collider/CCPhysicsBoxCollider.js
index 6cadd5a5481..5d6e01134c8 100644
--- a/cocos2d/core/physics/collider/CCPhysicsBoxCollider.js
+++ b/cocos2d/core/physics/collider/CCPhysicsBoxCollider.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/physics/collider/CCPhysicsChainCollider.js b/cocos2d/core/physics/collider/CCPhysicsChainCollider.js
index 52dfd2dfbab..3db9e9d75ea 100644
--- a/cocos2d/core/physics/collider/CCPhysicsChainCollider.js
+++ b/cocos2d/core/physics/collider/CCPhysicsChainCollider.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -88,8 +88,10 @@ var PhysicsChainCollider = cc.Class({
return shape;
},
- resetInEditor: CC_EDITOR && function () {
- this.resetPointsByContour();
+ resetInEditor: CC_EDITOR && function (didResetToDefault) {
+ if (didResetToDefault) {
+ this.resetPointsByContour();
+ }
},
resetPointsByContour: CC_EDITOR && function () {
diff --git a/cocos2d/core/physics/collider/CCPhysicsCircleCollider.js b/cocos2d/core/physics/collider/CCPhysicsCircleCollider.js
index bc064a3a8e9..c59410321a3 100644
--- a/cocos2d/core/physics/collider/CCPhysicsCircleCollider.js
+++ b/cocos2d/core/physics/collider/CCPhysicsCircleCollider.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/physics/collider/CCPhysicsCollider.js b/cocos2d/core/physics/collider/CCPhysicsCollider.js
index 956967d2aaa..03a5e7a311e 100644
--- a/cocos2d/core/physics/collider/CCPhysicsCollider.js
+++ b/cocos2d/core/physics/collider/CCPhysicsCollider.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/physics/collider/CCPhysicsPolygonCollider.js b/cocos2d/core/physics/collider/CCPhysicsPolygonCollider.js
index dd1dc31809d..ebe0681a147 100644
--- a/cocos2d/core/physics/collider/CCPhysicsPolygonCollider.js
+++ b/cocos2d/core/physics/collider/CCPhysicsPolygonCollider.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/physics/index.js b/cocos2d/core/physics/index.js
index dcaf6a1949f..fc556874671 100644
--- a/cocos2d/core/physics/index.js
+++ b/cocos2d/core/physics/index.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/physics/joint/CCDistanceJoint.js b/cocos2d/core/physics/joint/CCDistanceJoint.js
index ad35605226d..360816a313d 100644
--- a/cocos2d/core/physics/joint/CCDistanceJoint.js
+++ b/cocos2d/core/physics/joint/CCDistanceJoint.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -98,7 +98,6 @@ var DistanceJoint = cc.Class({
* !#zh
* 阻尼,表示关节变形后,恢复到初始状态受到的阻力。
* @property {Number} dampingRatio
- * @property 0
*/
dampingRatio: {
tooltip: CC_DEV && 'i18n:COMPONENT.physics.physics_collider.dampingRatio',
diff --git a/cocos2d/core/physics/joint/CCJoint.js b/cocos2d/core/physics/joint/CCJoint.js
index e4f0e5521bf..96e3eed5fc8 100644
--- a/cocos2d/core/physics/joint/CCJoint.js
+++ b/cocos2d/core/physics/joint/CCJoint.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/physics/joint/CCMotorJoint.js b/cocos2d/core/physics/joint/CCMotorJoint.js
index 58ab320a1f8..c2a2afc7b4e 100644
--- a/cocos2d/core/physics/joint/CCMotorJoint.js
+++ b/cocos2d/core/physics/joint/CCMotorJoint.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/physics/joint/CCMouseJoint.js b/cocos2d/core/physics/joint/CCMouseJoint.js
index d6c80698907..f66f20c5b49 100644
--- a/cocos2d/core/physics/joint/CCMouseJoint.js
+++ b/cocos2d/core/physics/joint/CCMouseJoint.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -211,6 +211,7 @@ var MouseJoint = cc.Class({
mouseRegion.on(cc.Node.EventType.TOUCH_START, this.onTouchBegan, this);
mouseRegion.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
mouseRegion.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
+ mouseRegion.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
},
onEnable: function () {
@@ -224,7 +225,7 @@ var MouseJoint = cc.Class({
var target = this._pressPoint = event.touch.getLocation();
if (cc.Camera && cc.Camera.main) {
- target = cc.Camera.main.getCameraToWorldPoint(target);
+ target = cc.Camera.main.getScreenToWorldPoint(target);
}
var collider = manager.testPoint( target );
@@ -266,7 +267,7 @@ var MouseJoint = cc.Class({
var camera = cc.Camera.findCamera(this.node);
if (camera) {
- this.target = camera.getCameraToWorldPoint(this._pressPoint);
+ this.target = camera.getScreenToWorldPoint(this._pressPoint);
}
else {
this.target = this._pressPoint;
diff --git a/cocos2d/core/physics/joint/CCPrismaticJoint.js b/cocos2d/core/physics/joint/CCPrismaticJoint.js
index 0fe4867c517..46f199eaddd 100644
--- a/cocos2d/core/physics/joint/CCPrismaticJoint.js
+++ b/cocos2d/core/physics/joint/CCPrismaticJoint.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/physics/joint/CCRevoluteJoint.js b/cocos2d/core/physics/joint/CCRevoluteJoint.js
index 61d3aca3ffa..4443ab89b37 100644
--- a/cocos2d/core/physics/joint/CCRevoluteJoint.js
+++ b/cocos2d/core/physics/joint/CCRevoluteJoint.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -199,9 +199,9 @@ var RevoluteJoint = cc.Class({
},
/**
- * #!en
+ * !#en
* Set the max and min limit angle.
- * #!zh
+ * !#zh
* 设置关节的角度最大和最小角度。
* @param {Number} lower
* @param {Number} upper
diff --git a/cocos2d/core/physics/joint/CCRopeJoint.js b/cocos2d/core/physics/joint/CCRopeJoint.js
index e61c6ba4245..8c6a0c00a83 100644
--- a/cocos2d/core/physics/joint/CCRopeJoint.js
+++ b/cocos2d/core/physics/joint/CCRopeJoint.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/physics/joint/CCWeldJoint.js b/cocos2d/core/physics/joint/CCWeldJoint.js
index 64357a31405..3f1fab8f174 100644
--- a/cocos2d/core/physics/joint/CCWeldJoint.js
+++ b/cocos2d/core/physics/joint/CCWeldJoint.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/physics/joint/CCWheelJoint.js b/cocos2d/core/physics/joint/CCWheelJoint.js
index 203a1710e67..30be8c67aa4 100644
--- a/cocos2d/core/physics/joint/CCWheelJoint.js
+++ b/cocos2d/core/physics/joint/CCWheelJoint.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -149,7 +149,7 @@ var WheelJoint = cc.Class({
set: function (value) {
this._frequency = value;
if (this._joint) {
- this._joint.SetFrequency(value);
+ this._joint.SetSpringFrequencyHz(value);
}
}
},
diff --git a/cocos2d/core/physics/platform/CCPhysicsAABBQueryCallback.js b/cocos2d/core/physics/platform/CCPhysicsAABBQueryCallback.js
index d922e7c7534..e2ff080ad6f 100644
--- a/cocos2d/core/physics/platform/CCPhysicsAABBQueryCallback.js
+++ b/cocos2d/core/physics/platform/CCPhysicsAABBQueryCallback.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/physics/platform/CCPhysicsContactListner.js b/cocos2d/core/physics/platform/CCPhysicsContactListner.js
index efbb13ed759..aef770cc183 100644
--- a/cocos2d/core/physics/platform/CCPhysicsContactListner.js
+++ b/cocos2d/core/physics/platform/CCPhysicsContactListner.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/physics/platform/CCPhysicsDebugDraw.js b/cocos2d/core/physics/platform/CCPhysicsDebugDraw.js
index 19bf79397b0..9ca184c68c7 100644
--- a/cocos2d/core/physics/platform/CCPhysicsDebugDraw.js
+++ b/cocos2d/core/physics/platform/CCPhysicsDebugDraw.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/physics/platform/CCPhysicsRayCastCallback.js b/cocos2d/core/physics/platform/CCPhysicsRayCastCallback.js
index 05581e4e95d..cbda32ac9bd 100644
--- a/cocos2d/core/physics/platform/CCPhysicsRayCastCallback.js
+++ b/cocos2d/core/physics/platform/CCPhysicsRayCastCallback.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/physics/utils.js b/cocos2d/core/physics/utils.js
index 70316c1ef96..a717b36df7a 100644
--- a/cocos2d/core/physics/utils.js
+++ b/cocos2d/core/physics/utils.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -24,13 +24,13 @@
****************************************************************************/
function getWorldRotation (node) {
- var rot = node.rotationX;
+ var rot = node.angle;
var parent = node.parent;
while(parent.parent){
- rot += parent.rotationX;
+ rot += parent.angle;
parent = parent.parent;
}
- return rot;
+ return -rot;
}
function getWorldScale (node) {
@@ -49,10 +49,10 @@ function getWorldScale (node) {
}
function convertToNodeRotation (node, rotation) {
- rotation -= node.rotationX;
+ rotation -= -node.angle;
var parent = node.parent;
while(parent.parent){
- rotation -= parent.rotationX;
+ rotation -= -parent.angle;
parent = parent.parent;
}
return rotation;
diff --git a/cocos2d/core/platform/BKInputManager.js b/cocos2d/core/platform/BKInputManager.js
deleted file mode 100644
index d1c93ea41f2..00000000000
--- a/cocos2d/core/platform/BKInputManager.js
+++ /dev/null
@@ -1,439 +0,0 @@
-/****************************************************************************
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-if (CC_QQPLAY) {
-
- var js = require('../platform/js');
- var macro = require('./CCMacro');
- var sys = require('./CCSys');
- var eventManager = require('../event-manager');
-
- var TOUCH_TIMEOUT = macro.TOUCH_TIMEOUT;
-
- /**
- * This class manages all events of input. include: touch, mouse, accelerometer, keyboard
- */
- var bkInputManager = {
- _isRegisterEvent: false,
-
- _preTouchPoint: cc.v2(0, 0),
-
- _preTouchPool: [],
- _preTouchPoolPointer: 0,
-
- _touches: [],
- _touchesIntegerDict: {},
-
- _indexBitsUsed: 0,
- _maxTouches: 5,
-
- _getUnUsedIndex: function () {
- var temp = this._indexBitsUsed;
- var now = cc.sys.now();
-
- for (var i = 0; i < this._maxTouches; i++) {
- if (!(temp & 0x00000001)) {
- this._indexBitsUsed |= (1 << i);
- return i;
- }
- else {
- var touch = this._touches[i];
- if (now - touch._lastModified > TOUCH_TIMEOUT) {
- this._removeUsedIndexBit(i);
- delete this._touchesIntegerDict[touch.getID()];
- return i;
- }
- }
- temp >>= 1;
- }
-
- // all bits are used
- return -1;
- },
-
- _removeUsedIndexBit: function (index) {
- if (index < 0 || index >= this._maxTouches)
- return;
-
- var temp = 1 << index;
- temp = ~temp;
- this._indexBitsUsed &= temp;
- },
-
- _glView: null,
-
- /**
- * @method handleTouchesBegin
- * @param {Array} touches
- */
- handleTouchesBegin: function (touches) {
- var selTouch, index, curTouch, touchID,
- handleTouches = [], locTouchIntDict = this._touchesIntegerDict,
- now = sys.now();
- for (var i = 0, len = touches.length; i < len; i++) {
- selTouch = touches[i];
- touchID = selTouch.getID();
- index = locTouchIntDict[touchID];
-
- if (index == null) {
- var unusedIndex = this._getUnUsedIndex();
- if (unusedIndex === -1) {
- cc.logID(2300, unusedIndex);
- continue;
- }
- //curTouch = this._touches[unusedIndex] = selTouch;
- curTouch = this._touches[unusedIndex] = new cc.Touch(selTouch._point.x, selTouch._point.y, selTouch.getID());
- curTouch._lastModified = now;
- curTouch._setPrevPoint(selTouch._prevPoint);
- locTouchIntDict[touchID] = unusedIndex;
- handleTouches.push(curTouch);
- }
- }
- if (handleTouches.length > 0) {
- this._glView._convertTouchesWithScale(handleTouches);
- var touchEvent = new cc.Event.EventTouch(handleTouches);
- touchEvent._eventCode = cc.Event.EventTouch.BEGAN;
- eventManager.dispatchEvent(touchEvent);
- }
- },
-
- /**
- * @method handleTouchesMove
- * @param {Array} touches
- */
- handleTouchesMove: function (touches) {
- var selTouch, index, touchID,
- handleTouches = [], locTouches = this._touches,
- now = sys.now();
- for (var i = 0, len = touches.length; i < len; i++) {
- selTouch = touches[i];
- touchID = selTouch.getID();
- index = this._touchesIntegerDict[touchID];
-
- if (index == null) {
- //cc.log("if the index doesn't exist, it is an error");
- continue;
- }
- if (locTouches[index]) {
- locTouches[index]._setPoint(selTouch._point);
- locTouches[index]._setPrevPoint(selTouch._prevPoint);
- locTouches[index]._lastModified = now;
- handleTouches.push(locTouches[index]);
- }
- }
- if (handleTouches.length > 0) {
- this._glView._convertTouchesWithScale(handleTouches);
- var touchEvent = new cc.Event.EventTouch(handleTouches);
- touchEvent._eventCode = cc.Event.EventTouch.MOVED;
- eventManager.dispatchEvent(touchEvent);
- }
- },
-
- /**
- * @method handleTouchesEnd
- * @param {Array} touches
- */
- handleTouchesEnd: function (touches) {
- var handleTouches = this.getSetOfTouchesEndOrCancel(touches);
- if (handleTouches.length > 0) {
- this._glView._convertTouchesWithScale(handleTouches);
- var touchEvent = new cc.Event.EventTouch(handleTouches);
- touchEvent._eventCode = cc.Event.EventTouch.ENDED;
- eventManager.dispatchEvent(touchEvent);
- }
- },
-
- /**
- * @method handleTouchesCancel
- * @param {Array} touches
- */
- handleTouchesCancel: function (touches) {
- var handleTouches = this.getSetOfTouchesEndOrCancel(touches);
- if (handleTouches.length > 0) {
- this._glView._convertTouchesWithScale(handleTouches);
- var touchEvent = new cc.Event.EventTouch(handleTouches);
- touchEvent._eventCode = cc.Event.EventTouch.CANCELLED;
- eventManager.dispatchEvent(touchEvent);
- }
- },
-
- /**
- * @method getSetOfTouchesEndOrCancel
- * @param {Array} touches
- * @returns {Array}
- */
- getSetOfTouchesEndOrCancel: function (touches) {
- var selTouch, index, touchID, handleTouches = [], locTouches = this._touches,
- locTouchesIntDict = this._touchesIntegerDict;
- for (var i = 0, len = touches.length; i < len; i++) {
- selTouch = touches[i];
- touchID = selTouch.getID();
- index = locTouchesIntDict[touchID];
-
- if (index == null) {
- continue; //cc.log("if the index doesn't exist, it is an error");
- }
- if (locTouches[index]) {
- locTouches[index]._setPoint(selTouch._point);
- locTouches[index]._setPrevPoint(selTouch._prevPoint);
- handleTouches.push(locTouches[index]);
- this._removeUsedIndexBit(index);
- delete locTouchesIntDict[touchID];
- }
- }
- return handleTouches;
- },
-
- /**
- * @method getHTMLElementPosition
- * @param {HTMLElement} element
- * @return {Object}
- */
- getHTMLElementPosition: function (element) {
- var docElem = document.documentElement;
- var leftOffset = window.pageXOffset - docElem.clientLeft;
- var topOffset = window.pageYOffset - docElem.clientTop;
- if (typeof element.getBoundingClientRect === 'function') {
- var box = element.getBoundingClientRect();
- return {
- left: box.left + leftOffset,
- top: box.top + topOffset,
- width: box.width,
- height: box.height
- };
- }
- else {
- if (element instanceof HTMLCanvasElement) {
- return {
- left: leftOffset,
- top: topOffset,
- width: element.width,
- height: element.height
- };
- }
- else {
- return {
- left: leftOffset,
- top: topOffset,
- width: parseInt(element.style.width),
- height: parseInt(element.style.height)
- };
- }
- }
- },
-
- /**
- * @method getPreTouch
- * @param {Touch} touch
- * @return {Touch}
- */
- getPreTouch: function (touch) {
- var preTouch = null;
- var locPreTouchPool = this._preTouchPool;
- var id = touch.getID();
- for (var i = locPreTouchPool.length - 1; i >= 0; i--) {
- if (locPreTouchPool[i].getID() === id) {
- preTouch = locPreTouchPool[i];
- break;
- }
- }
- if (!preTouch)
- preTouch = touch;
- return preTouch;
- },
-
- /**
- * @method setPreTouch
- * @param {Touch} touch
- */
- setPreTouch: function (touch) {
- var find = false;
- var locPreTouchPool = this._preTouchPool;
- var id = touch.getID();
- for (var i = locPreTouchPool.length - 1; i >= 0; i--) {
- if (locPreTouchPool[i].getID() === id) {
- locPreTouchPool[i] = touch;
- find = true;
- break;
- }
- }
- if (!find) {
- if (locPreTouchPool.length <= 50) {
- locPreTouchPool.push(touch);
- }
- else {
- locPreTouchPool[this._preTouchPoolPointer] = touch;
- this._preTouchPoolPointer = (this._preTouchPoolPointer + 1) % 50;
- }
- }
- },
-
- /**
- * @method getTouchByXY
- * @param {Number} tx
- * @param {Number} ty
- * @param {Vec2} pos
- * @return {Touch}
- */
- getTouchByXY: function (tx, ty, pos) {
- var locPreTouch = this._preTouchPoint;
- var location = this._glView.convertToLocationInView(tx, ty, pos);
- var touch = new cc.Touch(location.x, location.y);
- touch._setPrevPoint(locPreTouch.x, locPreTouch.y);
- locPreTouch.x = location.x;
- locPreTouch.y = location.y;
- return touch;
- },
-
- /**
- * @method getPointByEvent
- * @param {Touch} event
- * @param {Vec2} pos
- * @return {Vec2}
- */
- getPointByEvent: function (event, pos) {
- if (event.pageX != null) //not avalable in <= IE8
- return {
- x: event.pageX,
- y: event.pageY
- };
-
- pos.left -= document.body.scrollLeft;
- pos.top -= document.body.scrollTop;
-
- return {
- x: event.clientX,
- y: event.clientY
- };
- },
-
- /**
- * @method getTouchesByEvent
- * @param {Touch} event
- * @param {Vec2} pos
- * @returns {Array}
- */
- getTouchesByEvent: function (event) {
- var touchArr = [], locView = this._glView;
- var touch_event, touch, preLocation;
- var locPreTouch = this._preTouchPoint;
- var length = event.length;
- for (var i = 0; i < length; i++) {
- touch_event = event[i];
- if (touch_event) {
-
- var location = locView.convertToLocationInView(touch_event.x, touch_event.y, this._relatedPos);
- location.y = cc.game.canvas.height - location.y;
- if (touch_event.id != null) {
- touch = new cc.Touch(location.x, location.y, touch_event.id);
- //use Touch Pool
- preLocation = this.getPreTouch(touch).getLocation();
- touch._setPrevPoint(preLocation.x, preLocation.y);
- this.setPreTouch(touch);
- }
- else {
- touch = new cc.Touch(location.x, location.y);
- touch._setPrevPoint(locPreTouch.x, locPreTouch.y);
- }
- locPreTouch.x = location.x;
- locPreTouch.y = location.y;
- touchArr.push(touch);
- }
- }
- return touchArr;
- },
-
- // bk game
- detectGesture: function () {
- var allTouchArr = BK.TouchEvent.getAllTouchEvent();
- if (!allTouchArr) {
- return;
- }
-
- var _touchBeginEvents = [];
- var _touchMoveEvents = [];
- var _touchEndEvents = [];
-
- var touchArr = allTouchArr;
- for(var i = 0; i < touchArr.length; i++) {
- _touchBeginEvents.length = 0;
- _touchMoveEvents.length = 0;
- _touchEndEvents.length = 0;
-
- for (var j = 0; j < touchArr[i].length; ++j) {
-
- var touch_event = touchArr[i][j];
- //touch begin
- if (touch_event.status === 2) {
- _touchBeginEvents.push(touch_event);
- }
- //touch moved
- else if (touch_event.status === 3) {
- _touchMoveEvents.push(touch_event);
- }
- //touch end
- else if (touch_event.status === 1) {
- _touchEndEvents.push(touch_event);
- }
- }
-
- if (_touchBeginEvents.length > 0) {
- this.handleTouchesBegin(this.getTouchesByEvent(_touchBeginEvents));
- }
- if (_touchMoveEvents.length > 0) {
- this.handleTouchesMove(this.getTouchesByEvent(_touchMoveEvents));
- }
- if (_touchEndEvents.length > 0) {
- this.handleTouchesEnd(this.getTouchesByEvent(_touchEndEvents));
- }
-
- }
-
- },
-
- /**
- * @method registerSystemEvent
- * @param {HTMLElement} element
- */
- registerSystemEvent: function (element) {
- this._glView = cc.view;
- this._relatedPos = {
- left: 0,
- top: 0,
- width: element.width,
- height: element.height
- };
- BK.Script.getTouchModeAll = 1;
- },
-
- _registerKeyboardEvent: function () {
- },
-
- _registerAccelerometerEvent: function () {
- },
- };
-
- module.exports = BK.inputManager = bkInputManager;
-}
diff --git a/cocos2d/core/platform/CCAssetLibrary.js b/cocos2d/core/platform/CCAssetLibrary.js
deleted file mode 100644
index 9d5776b28d0..00000000000
--- a/cocos2d/core/platform/CCAssetLibrary.js
+++ /dev/null
@@ -1,381 +0,0 @@
-/****************************************************************************
- Copyright (c) 2013-2016 Chukong Technologies Inc.
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-var Asset = require('../assets/CCAsset');
-var callInNextTick = require('./utils').callInNextTick;
-var Loader = require('../load-pipeline/CCLoader');
-var PackDownloader = require('../load-pipeline/pack-downloader');
-var AutoReleaseUtils = require('../load-pipeline/auto-release-utils');
-var decodeUuid = require('../utils/decode-uuid');
-var MD5Pipe = require('../load-pipeline/md5-pipe');
-var js = require('./js');
-
-/**
- * The asset library which managing loading/unloading assets in project.
- *
- * @class AssetLibrary
- * @static
- */
-
-// configs
-
-var _libraryBase = '';
-var _rawAssetsBase = ''; // The base dir for raw assets in runtime
-var _uuidToRawAsset = js.createMap(true);
-
-function isScene (asset) {
- return asset && (asset.constructor === cc.SceneAsset || asset instanceof cc.Scene);
-}
-
-// types
-
-function RawAssetEntry (url, type) {
- this.url = url;
- this.type = type;
-}
-
-// publics
-
-var AssetLibrary = {
- /**
- * @callback loadCallback
- * @param {String} error - null or the error info
- * @param {Asset} data - the loaded asset or null
- */
-
- /**
- * @method loadAsset
- * @param {String} uuid
- * @param {loadCallback} callback - the callback function once load finished
- * @param {Object} options
- * @param {Boolean} options.readMainCache - Default is true. If false, the asset and all its depends assets will reload and create new instances from library.
- * @param {Boolean} options.writeMainCache - Default is true. If true, the result will cache to AssetLibrary, and MUST be unload by user manually.
- * @param {Asset} options.existingAsset - load to existing asset, this argument is only available in editor
- * @private
- */
- loadAsset: function (uuid, callback, options) {
- if (typeof uuid !== 'string') {
- return callInNextTick(callback, new Error('[AssetLibrary] uuid must be string'), null);
- }
- // var readMainCache = typeof (options && options.readMainCache) !== 'undefined' ? readMainCache : true;
- // var writeMainCache = typeof (options && options.writeMainCache) !== 'undefined' ? writeMainCache : true;
- var item = {
- uuid: uuid,
- type: 'uuid'
- };
- if (options && options.existingAsset) {
- item.existingAsset = options.existingAsset;
- }
- Loader.load(item, function (error, asset) {
- if (error || !asset) {
- error = new Error('[AssetLibrary] loading JSON or dependencies failed: ' + (error ? error.message : 'Unknown error'));
- }
- else {
- if (asset.constructor === cc.SceneAsset) {
- if (CC_EDITOR && !asset.scene) {
- Editor.error('Sorry, the scene data of "%s" is corrupted!', uuid);
- }
- else {
- var key = cc.loader._getReferenceKey(uuid);
- asset.scene.dependAssets = AutoReleaseUtils.getDependsRecursively(key);
- }
- }
- if (CC_EDITOR || isScene(asset)) {
- var id = cc.loader._getReferenceKey(uuid);
- Loader.removeItem(id);
- }
- }
- if (callback) {
- callback(error, asset);
- }
- });
- },
-
- getLibUrlNoExt: function (uuid, inRawAssetsDir) {
- if (CC_BUILD) {
- uuid = decodeUuid(uuid);
- }
- var base = (CC_BUILD && inRawAssetsDir) ? (_rawAssetsBase + 'assets/') : _libraryBase;
- return base + uuid.slice(0, 2) + '/' + uuid;
- },
-
- _queryAssetInfoInEditor: function (uuid, callback) {
- if (CC_EDITOR) {
- Editor.Ipc.sendToMain('scene:query-asset-info-by-uuid', uuid, function (err, info) {
- if (info) {
- Editor.Utils.UuidCache.cache(info.url, uuid);
- var ctor = Editor.assets[info.type];
- if (ctor) {
- var isRawAsset = !js.isChildClassOf(ctor, Asset);
- callback(null, info.url, isRawAsset, ctor);
- }
- else {
- callback(new Error('Can not find asset type ' + info.type));
- }
- }
- else {
- var error = new Error('Can not get asset url by uuid "' + uuid + '", the asset may be deleted.');
- error.errorCode = 'db.NOTFOUND';
- callback(error);
- }
- });
- }
- },
-
- _getAssetInfoInRuntime: function (uuid, result) {
- result = result || {url: null, raw: false};
- var info = _uuidToRawAsset[uuid];
- if (info && !js.isChildClassOf(info.type, cc.Asset)) {
- // backward compatibility since 1.10
- result.url = _rawAssetsBase + info.url;
- result.raw = true;
- }
- else {
- result.url = this.getLibUrlNoExt(uuid) + '.json';
- result.raw = false;
- }
- return result;
- },
-
- _uuidInSettings: function (uuid) {
- return uuid in _uuidToRawAsset;
- },
-
- /**
- * @method queryAssetInfo
- * @param {String} uuid
- * @param {Function} callback
- * @param {Error} callback.error
- * @param {String} callback.url - the url of raw asset or imported asset
- * @param {Boolean} callback.raw - indicates whether the asset is raw asset
- * @param {Function} callback.ctorInEditor - the actual type of asset, used in editor only
- */
- queryAssetInfo: function (uuid, callback) {
- if (CC_EDITOR && !CC_TEST) {
- this._queryAssetInfoInEditor(uuid, callback);
- }
- else {
- var info = this._getAssetInfoInRuntime(uuid);
- callback(null, info.url, info.raw);
- }
- },
-
- // parse uuid out of url
- parseUuidInEditor: function (url) {
- if (CC_EDITOR) {
- var uuid = '';
- var isImported = url.startsWith(_libraryBase);
- if (isImported) {
- var dir = cc.path.dirname(url);
- var dirBasename = cc.path.basename(dir);
-
- var isAssetUrl = dirBasename.length === 2;
- if (isAssetUrl) {
- uuid = cc.path.basename(url);
- var index = uuid.indexOf('.');
- if (index !== -1) {
- uuid = uuid.slice(0, index);
- }
- }
- else {
- // raw file url
- uuid = dirBasename;
- }
- }
- // If url is not in the library, just return ""
- return uuid;
- }
- },
-
- /**
- * @method loadJson
- * @param {String} json
- * @param {loadCallback} callback
- * @return {LoadingHandle}
- * @private
- */
- loadJson: function (json, callback) {
- var randomUuid = '' + ((new Date()).getTime() + Math.random());
- var item = {
- uuid: randomUuid,
- type: 'uuid',
- content: json,
- skips: [ Loader.assetLoader.id, Loader.downloader.id ]
- };
- Loader.load(item, function (error, asset) {
- if (error) {
- error = new Error('[AssetLibrary] loading JSON or dependencies failed: ' + error.message);
- }
- else {
- if (asset.constructor === cc.SceneAsset) {
- var key = cc.loader._getReferenceKey(randomUuid);
- asset.scene.dependAssets = AutoReleaseUtils.getDependsRecursively(key);
- }
- if (CC_EDITOR || isScene(asset)) {
- var id = cc.loader._getReferenceKey(randomUuid);
- Loader.removeItem(id);
- }
- }
- asset._uuid = '';
- if (callback) {
- callback(error, asset);
- }
- });
- },
-
- /**
- * Get the exists asset by uuid.
- *
- * @method getAssetByUuid
- * @param {String} uuid
- * @return {Asset} - the existing asset, if not loaded, just returns null.
- * @private
- */
- getAssetByUuid: function (uuid) {
- return AssetLibrary._uuidToAsset[uuid] || null;
- },
-
- /**
- * init the asset library
- *
- * @method init
- * @param {Object} options
- * @param {String} options.libraryPath - 能接收的任意类型的路径,通常在编辑器里使用绝对的,在网页里使用相对的。
- * @param {Object} options.mountPaths - mount point of actual urls for raw assets (only used in editor)
- * @param {Object} [options.rawAssets] - uuid to raw asset's urls (only used in runtime)
- * @param {String} [options.rawAssetsBase] - base of raw asset's urls (only used in runtime)
- * @param {String} [options.packedAssets] - packed assets (only used in runtime)
- */
- init: function (options) {
- if (CC_EDITOR && _libraryBase) {
- cc.errorID(6402);
- return;
- }
-
-
- // 这里将路径转 url,不使用路径的原因是有的 runtime 不能解析 "\" 符号。
- // 不使用 url.format 的原因是 windows 不支持 file:// 和 /// 开头的协议,所以只能用 replace 操作直接把路径转成 URL。
- var libraryPath = options.libraryPath;
- libraryPath = libraryPath.replace(/\\/g, '/');
- _libraryBase = cc.path.stripSep(libraryPath) + '/';
-
- _rawAssetsBase = options.rawAssetsBase;
-
- var md5AssetsMap = options.md5AssetsMap;
- if (md5AssetsMap && md5AssetsMap.import) {
- // decode uuid
- var i = 0, uuid = 0;
- var md5ImportMap = js.createMap(true);
- var md5Entries = md5AssetsMap.import;
- for (i = 0; i < md5Entries.length; i += 2) {
- uuid = decodeUuid(md5Entries[i]);
- md5ImportMap[uuid] = md5Entries[i + 1];
- }
-
- var md5RawAssetsMap = js.createMap(true);
- md5Entries = md5AssetsMap['raw-assets'];
- for (i = 0; i < md5Entries.length; i += 2) {
- uuid = decodeUuid(md5Entries[i]);
- md5RawAssetsMap[uuid] = md5Entries[i + 1];
- }
-
- var md5Pipe = new MD5Pipe(md5ImportMap, md5RawAssetsMap, _libraryBase);
- cc.loader.insertPipeAfter(cc.loader.assetLoader, md5Pipe);
- cc.loader.md5Pipe = md5Pipe;
- }
-
- // init raw assets
-
- var resources = Loader._resources;
- resources.reset();
- var rawAssets = options.rawAssets;
- if (rawAssets) {
- for (var mountPoint in rawAssets) {
- var assets = rawAssets[mountPoint];
- for (var uuid in assets) {
- var info = assets[uuid];
- var url = info[0];
- var typeId = info[1];
- var type = cc.js._getClassById(typeId);
- if (!type) {
- cc.error('Cannot get', typeId);
- continue;
- }
- // backward compatibility since 1.10
- _uuidToRawAsset[uuid] = new RawAssetEntry(mountPoint + '/' + url, type);
- // init resources
- if (mountPoint === 'assets') {
- var ext = cc.path.extname(url);
- if (ext) {
- // trim base dir and extname
- url = url.slice(0, - ext.length);
- }
- var isSubAsset = info[2] === 1;
- // register
- resources.add(url, uuid, type, !isSubAsset);
- }
- }
- }
- }
-
- if (options.packedAssets) {
- PackDownloader.initPacks(options.packedAssets);
- }
-
- // init cc.url
- cc.url._init((options.mountPaths && options.mountPaths.assets) || _rawAssetsBase + 'assets');
- }
-};
-
-// unload asset if it is destoryed
-
-/**
- * !#en Caches uuid to all loaded assets in scenes.
- *
- * !#zh 这里保存所有已经加载的场景资源,防止同一个资源在内存中加载出多份拷贝。
- *
- * 这里用不了WeakMap,在浏览器中所有加载过的资源都只能手工调用 unloadAsset 释放。
- *
- * 参考:
- * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap
- * https://github.com/TooTallNate/node-weak
- *
- * @property {object} _uuidToAsset
- * @private
- */
-AssetLibrary._uuidToAsset = {};
-
-//暂时屏蔽,因为目前没有缓存任何asset
-//if (CC_DEV && Asset.prototype._onPreDestroy) {
-// cc.error('_onPreDestroy of Asset has already defined');
-//}
-//Asset.prototype._onPreDestroy = function () {
-// if (AssetLibrary._uuidToAsset[this._uuid] === this) {
-// AssetLibrary.unloadAsset(this);
-// }
-//};
-
-module.exports = cc.AssetLibrary = AssetLibrary;
diff --git a/cocos2d/core/platform/CCClass.js b/cocos2d/core/platform/CCClass.js
index d3d6486b7a0..14510951661 100644
--- a/cocos2d/core/platform/CCClass.js
+++ b/cocos2d/core/platform/CCClass.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -31,13 +31,12 @@ var _isPlainEmptyObj_DEV = utils.isPlainEmptyObj_DEV;
var _cloneable_DEV = utils.cloneable_DEV;
var Attr = require('./attribute');
var DELIMETER = Attr.DELIMETER;
-var getTypeChecker = Attr.getTypeChecker;
var preprocess = require('./preprocess-class');
require('./requiring-frame');
var BUILTIN_ENTRIES = ['name', 'extends', 'mixins', 'ctor', '__ctor__', 'properties', 'statics', 'editor', '__ES6__'];
-var INVALID_STATICS_DEV = CC_DEV && ['name', '__ctors__', '__props__', 'arguments', 'call', 'apply', 'caller',
+var INVALID_STATICS_DEV = CC_DEV && ['name', '__ctors__', '__props__', '__values__', 'arguments', 'call', 'apply', 'caller',
'length', 'prototype'];
function pushUnique (array, item) {
@@ -105,7 +104,6 @@ function appendProp (cls, name) {
pushUnique(cls.__props__, name);
}
-var tmpArray = [];
function defineProp (cls, className, propName, val, es6) {
var defaultValue = val.default;
@@ -145,26 +143,12 @@ function defineProp (cls, className, propName, val, es6) {
appendProp(cls, propName);
// apply attributes
- var attrs = parseAttributes(cls, val, className, propName, false);
- if (attrs) {
- var onAfterProp = tmpArray;
- for (var i = 0; i < attrs.length; i++) {
- var attr = attrs[i];
- Attr.attr(cls, propName, attr);
- if (attr['serializable'] === false) {
- pushUnique(cls.__values__, propName);
- }
- // register callback
- if (attr._onAfterProp) {
- onAfterProp.push(attr._onAfterProp);
- }
+ parseAttributes(cls, val, className, propName, false);
+ if ((CC_EDITOR && !Editor.isBuilder) || CC_TEST) {
+ for (let i = 0; i < onAfterProps_ET.length; i++) {
+ onAfterProps_ET[i](cls, propName);
}
- // call callback
- for (var c = 0; c < onAfterProp.length; c++) {
- onAfterProp[c](cls, propName);
- }
- tmpArray.length = 0;
- attrs.length = 0;
+ onAfterProps_ET.length = 0;
}
}
@@ -181,11 +165,10 @@ function defineGetSet (cls, name, propName, val, es6) {
return;
}
- var attrs = parseAttributes(cls, val, name, propName, true);
- for (var i = 0; i < attrs.length; i++) {
- Attr.attr(cls, propName, attrs[i]);
+ parseAttributes(cls, val, name, propName, true);
+ if ((CC_EDITOR && !Editor.isBuilder) || CC_TEST) {
+ onAfterProps_ET.length = 0;
}
- attrs.length = 0;
Attr.setClassAttr(cls, propName, 'serializable', false);
@@ -324,10 +307,7 @@ function doDefine (className, baseClass, mixins, options) {
// mixin attributes
if (CCClass._isCCClass(mixin)) {
- mixinWithInherited(
- Attr.getClassAttrs(fireClass).constructor.prototype,
- Attr.getClassAttrs(mixin).constructor.prototype
- );
+ mixinWithInherited(Attr.getClassAttrs(fireClass), Attr.getClassAttrs(mixin));
}
}
// restore constuctor overridden by mixin
@@ -490,63 +470,100 @@ function getInitPropsJit (attrs, propList) {
}
function getInitProps (attrs, propList) {
- var advancedProps = [];
- var advancedValues = [];
- var simpleProps = [];
- var simpleValues = [];
-
- for (var i = 0; i < propList.length; ++i) {
- var prop = propList[i];
- var attrKey = prop + DELIMETER + 'default';
- if (attrKey in attrs) { // getter does not have default
- var def = attrs[attrKey];
- if ((typeof def === 'object' && def) || typeof def === 'function') {
- advancedProps.push(prop);
- advancedValues.push(def);
- }
- else {
- // number, boolean, null, undefined, string
- simpleProps.push(prop);
- simpleValues.push(def);
+ var props = null;
+ var simpleEnd = 0;
+ var valueTypeEnd = 0;
+
+ (function () {
+
+ // triage properties
+
+ var simples = null;
+ var valueTypes = null;
+ var advanceds = null;
+
+ for (let i = 0; i < propList.length; ++i) {
+ var prop = propList[i];
+ var attrKey = prop + DELIMETER + 'default';
+ if (attrKey in attrs) { // getter does not have default
+ var def = attrs[attrKey];
+ if ((typeof def === 'object' && def) || typeof def === 'function') {
+ if (def instanceof cc.ValueType) {
+ if (!valueTypes) {
+ valueTypes = [];
+ }
+ valueTypes.push(prop, def);
+ }
+ else {
+ if (!advanceds) {
+ advanceds = [];
+ }
+ advanceds.push(prop, def);
+ }
+ }
+ else {
+ // number, boolean, null, undefined, string
+ if (!simples) {
+ simples = [];
+ }
+ simples.push(prop, def);
+ }
}
}
- }
+
+ // concat in compact memory
+
+ simpleEnd = simples ? simples.length : 0;
+ valueTypeEnd = simpleEnd + (valueTypes ? valueTypes.length : 0);
+ let totalLength = valueTypeEnd + (advanceds ? advanceds.length : 0);
+ props = new Array(totalLength);
+
+ for (let i = 0; i < simpleEnd; ++i) {
+ props[i] = simples[i];
+ }
+ for (let i = simpleEnd; i < valueTypeEnd; ++i) {
+ props[i] = valueTypes[i - simpleEnd];
+ }
+ for (let i = valueTypeEnd; i < totalLength; ++i) {
+ props[i] = advanceds[i - valueTypeEnd];
+ }
+ })();
return function () {
- for (let i = 0; i < simpleProps.length; ++i) {
- this[simpleProps[i]] = simpleValues[i];
+ let i = 0;
+ for (; i < simpleEnd; i += 2) {
+ this[props[i]] = props[i + 1];
}
- for (let i = 0; i < advancedProps.length; i++) {
- let prop = advancedProps[i];
- var expression;
- var def = advancedValues[i];
- if (typeof def === 'object') {
- if (def instanceof cc.ValueType) {
- expression = def.clone();
- }
- else if (Array.isArray(def)) {
- expression = [];
- }
- else {
- expression = {};
- }
+ for (; i < valueTypeEnd; i += 2) {
+ this[props[i]] = props[i + 1].clone();
+ }
+ for (; i < props.length; i += 2) {
+ var def = props[i + 1];
+ if (Array.isArray(def)) {
+ this[props[i]] = [];
}
else {
- // def is function
- if (CC_EDITOR) {
- try {
- expression = def();
- }
- catch (err) {
- cc._throw(e);
- continue;
- }
+ var value;
+ if (typeof def === 'object') {
+ value = {};
}
else {
- expression = def();
+ // def is function
+ if (CC_EDITOR) {
+ try {
+ value = def();
+ }
+ catch (err) {
+ cc._throw(e);
+ continue;
+ }
+ }
+ else {
+ value = def();
+ }
}
+ this[props[i]] = value;
}
- this[prop] = expression;
}
};
}
@@ -907,7 +924,7 @@ function declareProperties (cls, className, properties, baseClass, mixins, es6)
properties {
width: {
default: 128,
- type: 'Integer',
+ type: cc.Integer,
tooltip: 'The width of sprite'
},
height: 128,
@@ -1037,11 +1054,11 @@ CCClass._fastDefine = function (className, constructor, serializableFields) {
js.setClassName(className, constructor);
//constructor.__ctors__ = constructor.__ctors__ || null;
var props = constructor.__props__ = constructor.__values__ = Object.keys(serializableFields);
- var attrProtos = Attr.getClassAttrsProto(constructor);
+ var attrs = Attr.getClassAttrs(constructor);
for (var i = 0; i < props.length; i++) {
var key = props[i];
- attrProtos[key + DELIMETER + 'visible'] = false;
- attrProtos[key + DELIMETER + 'default'] = serializableFields[key];
+ attrs[key + DELIMETER + 'visible'] = false;
+ attrs[key + DELIMETER + 'default'] = serializableFields[key];
}
};
@@ -1077,28 +1094,29 @@ var PrimitiveTypes = {
Boolean: 'Boolean',
String: 'String',
};
-var tmpAttrs = [];
-function parseAttributes (cls, attrs, className, propName, usedInGetter) {
+var onAfterProps_ET = [];
+function parseAttributes (cls, attributes, className, propName, usedInGetter) {
var ERR_Type = CC_DEV ? 'The %s of %s must be type %s' : '';
- var attrsProto = null;
- var attrsProtoKey = '';
- function getAttrsProto () {
- attrsProtoKey = propName + DELIMETER;
- return attrsProto = Attr.getClassAttrsProto(cls);
+ var attrs = null;
+ var propNamePrefix = '';
+ function initAttrs () {
+ propNamePrefix = propName + DELIMETER;
+ return attrs = Attr.getClassAttrs(cls);
}
- tmpAttrs.length = 0;
- var result = tmpAttrs;
+ if ((CC_EDITOR && !Editor.isBuilder) || CC_TEST) {
+ onAfterProps_ET.length = 0;
+ }
- var type = attrs.type;
+ var type = attributes.type;
if (type) {
var primitiveType = PrimitiveTypes[type];
if (primitiveType) {
- result.push({
- type: type,
- _onAfterProp: getTypeChecker(primitiveType, 'cc.' + type)
- });
+ (attrs || initAttrs())[propNamePrefix + 'type'] = type;
+ if (((CC_EDITOR && !Editor.isBuilder) || CC_TEST) && !attributes._short) {
+ onAfterProps_ET.push(Attr.getTypeChecker_ET(primitiveType, 'cc.' + type));
+ }
}
else if (type === 'Object') {
if (CC_DEV) {
@@ -1107,35 +1125,24 @@ function parseAttributes (cls, attrs, className, propName, usedInGetter) {
}
else {
if (type === Attr.ScriptUuid) {
- var attr = Attr.ObjectType(cc.ScriptAsset);
- attr.type = 'Script';
- result.push(attr);
+ (attrs || initAttrs())[propNamePrefix + 'type'] = 'Script';
+ attrs[propNamePrefix + 'ctor'] = cc.ScriptAsset;
}
else {
if (typeof type === 'object') {
if (Enum.isEnum(type)) {
- result.push({
- type: 'Enum',
- enumList: Enum.getList(type)
- });
+ (attrs || initAttrs())[propNamePrefix + 'type'] = 'Enum';
+ attrs[propNamePrefix + 'enumList'] = Enum.getList(type);
}
else if (CC_DEV) {
cc.errorID(3645, className, propName, type);
}
}
else if (typeof type === 'function') {
- if (attrs.url) {
- result.push({
- type: 'Object',
- ctor: type,
- _onAfterProp: getTypeChecker('String', 'cc.String')
- });
- }
- else {
- result.push(attrs._short ? {
- type: 'Object',
- ctor: type
- } : Attr.ObjectType(type));
+ (attrs || initAttrs())[propNamePrefix + 'type'] = 'Object';
+ attrs[propNamePrefix + 'ctor'] = type;
+ if (((CC_EDITOR && !Editor.isBuilder) || CC_TEST) && !attributes._short) {
+ onAfterProps_ET.push(Attr.getObjTypeChecker_ET(type));
}
}
else if (CC_DEV) {
@@ -1146,10 +1153,10 @@ function parseAttributes (cls, attrs, className, propName, usedInGetter) {
}
function parseSimpleAttr (attrName, expectType) {
- if (attrName in attrs) {
- var val = attrs[attrName];
+ if (attrName in attributes) {
+ var val = attributes[attrName];
if (typeof val === expectType) {
- (attrsProto || getAttrsProto())[attrsProtoKey + attrName] = val;
+ (attrs || initAttrs())[propNamePrefix + attrName] = val;
}
else if (CC_DEV) {
cc.error(ERR_Type, attrName, className, propName, expectType);
@@ -1157,70 +1164,86 @@ function parseAttributes (cls, attrs, className, propName, usedInGetter) {
}
}
- if (attrs.editorOnly) {
+ if (attributes.editorOnly) {
if (CC_DEV && usedInGetter) {
cc.errorID(3613, "editorOnly", name, propName);
}
else {
- (attrsProto || getAttrsProto())[attrsProtoKey + 'editorOnly'] = true;
+ (attrs || initAttrs())[propNamePrefix + 'editorOnly'] = true;
}
}
//parseSimpleAttr('preventDeferredLoad', 'boolean');
if (CC_DEV) {
parseSimpleAttr('displayName', 'string');
parseSimpleAttr('multiline', 'boolean');
- if (attrs.readonly) {
- (attrsProto || getAttrsProto())[attrsProtoKey + 'readonly'] = true;
+ if (attributes.readonly) {
+ (attrs || initAttrs())[propNamePrefix + 'readonly'] = true;
}
parseSimpleAttr('tooltip', 'string');
parseSimpleAttr('slide', 'boolean');
}
- if (attrs.url) {
- (attrsProto || getAttrsProto())[attrsProtoKey + 'saveUrlAsAsset'] = true;
- }
- if (attrs.serializable === false) {
+ if (attributes.serializable === false) {
if (CC_DEV && usedInGetter) {
cc.errorID(3613, "serializable", name, propName);
}
else {
- (attrsProto || getAttrsProto())[attrsProtoKey + 'serializable'] = false;
+ (attrs || initAttrs())[propNamePrefix + 'serializable'] = false;
}
}
+
+ // if (CC_BUILD || CC_TEST) {
+ // let fsa = attributes.formerlySerializedAs;
+ // if (fsa) {
+ // // js.set(cls.prototype, fsa, function (val) {
+ // // this[propName] = val;
+ // // });
+ // (attrs || initAttrs())[propNamePrefix + 'formerlySerializedAs'] = fsa;
+ // // used by deserialize-compiled
+ // attrs[fsa + DELIMETER + 'deserializeAs'] = propName;
+ // cls.__FSA__ = true; // inheritable
+ // }
+ // }
+ // else {
+ // parseSimpleAttr('formerlySerializedAs', 'string');
+ // }
+
parseSimpleAttr('formerlySerializedAs', 'string');
if (CC_EDITOR) {
- if ('animatable' in attrs && !attrs.animatable) {
- (attrsProto || getAttrsProto())[attrsProtoKey + 'animatable'] = false;
+ parseSimpleAttr('notifyFor', 'string');
+
+ if ('animatable' in attributes) {
+ (attrs || initAttrs())[propNamePrefix + 'animatable'] = !!attributes.animatable;
}
}
if (CC_DEV) {
- var visible = attrs.visible;
+ var visible = attributes.visible;
if (typeof visible !== 'undefined') {
if (!visible) {
- (attrsProto || getAttrsProto())[attrsProtoKey + 'visible'] = false;
+ (attrs || initAttrs())[propNamePrefix + 'visible'] = false;
}
else if (typeof visible === 'function') {
- (attrsProto || getAttrsProto())[attrsProtoKey + 'visible'] = visible;
+ (attrs || initAttrs())[propNamePrefix + 'visible'] = visible;
}
}
else {
var startsWithUS = (propName.charCodeAt(0) === 95);
if (startsWithUS) {
- (attrsProto || getAttrsProto())[attrsProtoKey + 'visible'] = false;
+ (attrs || initAttrs())[propNamePrefix + 'visible'] = false;
}
}
}
- var range = attrs.range;
+ var range = attributes.range;
if (range) {
if (Array.isArray(range)) {
if (range.length >= 2) {
- (attrsProto || getAttrsProto())[attrsProtoKey + 'min'] = range[0];
- attrsProto[attrsProtoKey + 'max'] = range[1];
+ (attrs || initAttrs())[propNamePrefix + 'min'] = range[0];
+ attrs[propNamePrefix + 'max'] = range[1];
if (range.length > 2) {
- attrsProto[attrsProtoKey + 'step'] = range[2];
+ attrs[propNamePrefix + 'step'] = range[2];
}
}
else if (CC_DEV) {
@@ -1234,8 +1257,6 @@ function parseAttributes (cls, attrs, className, propName, usedInGetter) {
parseSimpleAttr('min', 'number');
parseSimpleAttr('max', 'number');
parseSimpleAttr('step', 'number');
-
- return result;
}
cc.Class = CCClass;
@@ -1249,7 +1270,7 @@ module.exports = {
getNewValueTypeCode: CC_SUPPORT_JIT && getNewValueTypeCodeJit,
IDENTIFIER_RE,
escapeForJS,
- getDefault: getDefault
+ getDefault,
};
if (CC_TEST) {
diff --git a/cocos2d/core/platform/CCClassDecorator.js b/cocos2d/core/platform/CCClassDecorator.js
index 14aaf61e575..1283ee48096 100644
--- a/cocos2d/core/platform/CCClassDecorator.js
+++ b/cocos2d/core/platform/CCClassDecorator.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -139,7 +139,7 @@ function extractActualDefaultValues (ctor) {
}
catch (e) {
if (CC_DEV) {
- cc.warnID(3652, js.getClassName(ctor), e);
+ cc.errorID(3652, js.getClassName(ctor), e);
}
return {};
}
@@ -148,18 +148,16 @@ function extractActualDefaultValues (ctor) {
function genProperty (ctor, properties, propName, options, desc, cache) {
var fullOptions;
+ var isGetset = desc && (desc.get || desc.set);
if (options) {
- fullOptions = CC_DEV ? Preprocess.getFullFormOfProperty(options, propName, js.getClassName(ctor)) :
- Preprocess.getFullFormOfProperty(options);
- fullOptions = fullOptions || options;
+ fullOptions = Preprocess.getFullFormOfProperty(options, isGetset);
}
var existsProperty = properties[propName];
- var prop = js.mixin(existsProperty || {}, fullOptions || {});
+ var prop = js.mixin(existsProperty || {}, fullOptions || options || {});
- var isGetset = desc && (desc.get || desc.set);
if (isGetset) {
// typescript or babel
- if (CC_DEV && options && (options.get || options.set)) {
+ if (CC_DEV && options && ((fullOptions || options).get || (fullOptions || options).set)) {
var errorProps = getSubDict(cache, 'errorProps');
if (!errorProps[propName]) {
errorProps[propName] = true;
@@ -214,8 +212,8 @@ function genProperty (ctor, properties, propName, options, desc, cache) {
}
}
- if (CC_DEV) {
- if (options && options.hasOwnProperty('default')) {
+ if ((CC_EDITOR && !Editor.isBuilder) || CC_TEST) {
+ if (!fullOptions && options && options.hasOwnProperty('default')) {
cc.warnID(3653, propName, js.getClassName(ctor));
// prop.default = options.default;
}
@@ -223,13 +221,6 @@ function genProperty (ctor, properties, propName, options, desc, cache) {
cc.warnID(3654, js.getClassName(ctor), propName);
// prop.default = fullOptions.hasOwnProperty('default') ? fullOptions.default : undefined;
}
- if (cc.RawAsset.wasRawAssetType(prop.url) &&
- prop._short &&
- isDefaultValueSpecified &&
- defaultValue == null
- ) {
- cc.warnID(3656, js.getClassName(ctor), propName);
- }
}
prop.default = defaultValue;
}
@@ -240,9 +231,9 @@ function genProperty (ctor, properties, propName, options, desc, cache) {
/**
* !#en
* Declare the standard [ES6 Class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes)
- * as CCClass, please see [Class](/docs/editors_and_tools/creator-chapters/scripting/class/) for details.
+ * as CCClass, please see [Class](../../../manual/en/scripting/class.html) for details.
* !#zh
- * 将标准写法的 [ES6 Class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) 声明为 CCClass,具体用法请参阅[类型定义](/docs/creator/scripting/class/)。
+ * 将标准写法的 [ES6 Class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) 声明为 CCClass,具体用法请参阅[类型定义](../../../manual/zh/scripting/class.html)。
*
* @method ccclass
* @param {String} [name] - The class name used for serialization.
@@ -311,9 +302,9 @@ var ccclass = checkCtorArgument(function (ctor, name) {
/**
* !#en
- * Declare property for [CCClass](/docs/editors_and_tools/creator-chapters/scripting/class/).
+ * Declare property for [CCClass](../../../manual/en/scripting/reference/attributes.html).
* !#zh
- * 定义 [CCClass](/docs/creator/scripting/class/) 所用的属性。
+ * 定义 [CCClass](../../../manual/zh/scripting/reference/attributes.html) 所用的属性。
*
* @method property
* @param {Object} [options] - an object with some property attributes
@@ -587,7 +578,7 @@ var disallowMultiple = (CC_DEV ? createEditorDecorator : createDummyDecorator)(c
* playOnFocus(): Function
* playOnFocus(_class: Function): void
*/
-var playOnFocus = (CC_DEV ? createEditorDecorator : createDummyDecorator)(checkCtorArgument, 'playOnFocus');
+var playOnFocus = (CC_DEV ? createEditorDecorator : createDummyDecorator)(checkCtorArgument, 'playOnFocus', true);
/**
* !#en
@@ -722,3 +713,8 @@ cc._decorator = module.exports = {
help,
mixins,
};
+
+// fix submodule pollute ...
+/**
+ * @submodule cc
+ */
diff --git a/cocos2d/core/platform/CCEnum.js b/cocos2d/core/platform/CCEnum.js
index 6e722f81374..5fbc6c9180e 100644
--- a/cocos2d/core/platform/CCEnum.js
+++ b/cocos2d/core/platform/CCEnum.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/platform/CCInputExtension.js b/cocos2d/core/platform/CCInputExtension.js
index 3bee4aaa707..73d24fb454b 100644
--- a/cocos2d/core/platform/CCInputExtension.js
+++ b/cocos2d/core/platform/CCInputExtension.js
@@ -73,6 +73,10 @@ inputManager.setAccelerometerEnabled = function (isEnable) {
_t._accelCurTime = 0;
scheduler.unscheduleUpdate(_t);
}
+
+ if (CC_JSB || CC_RUNTIME) {
+ jsb.device.setMotionEnabled(isEnable);
+ }
};
/**
@@ -83,6 +87,10 @@ inputManager.setAccelerometerEnabled = function (isEnable) {
inputManager.setAccelerometerInterval = function (interval) {
if (this._accelInterval !== interval) {
this._accelInterval = interval;
+
+ if (CC_JSB || CC_RUNTIME) {
+ jsb.device.setMotionInterval(interval);
+ }
}
};
diff --git a/cocos2d/core/platform/CCInputManager.js b/cocos2d/core/platform/CCInputManager.js
index c01fc498ca0..a1cc2098084 100644
--- a/cocos2d/core/platform/CCInputManager.js
+++ b/cocos2d/core/platform/CCInputManager.js
@@ -59,6 +59,15 @@ let inputManager = {
_acceleration: null,
_accelDeviceEvent: null,
+ _canvasBoundingRect: {
+ left: 0,
+ top: 0,
+ adjustedLeft: 0,
+ adjustedTop: 0,
+ width: 0,
+ height: 0,
+ },
+
_getUnUsedIndex () {
let temp = this._indexBitsUsed;
let now = cc.sys.now();
@@ -94,6 +103,34 @@ let inputManager = {
_glView: null,
+ _updateCanvasBoundingRect () {
+ let element = cc.game.canvas;
+ let canvasBoundingRect = this._canvasBoundingRect;
+
+ let docElem = document.documentElement;
+ let leftOffset = window.pageXOffset - docElem.clientLeft;
+ let topOffset = window.pageYOffset - docElem.clientTop;
+ if (element.getBoundingClientRect) {
+ let box = element.getBoundingClientRect();
+ canvasBoundingRect.left = box.left + leftOffset;
+ canvasBoundingRect.top = box.top + topOffset;
+ canvasBoundingRect.width = box.width;
+ canvasBoundingRect.height = box.height;
+ }
+ else if (element instanceof HTMLCanvasElement) {
+ canvasBoundingRect.left = leftOffset;
+ canvasBoundingRect.top = topOffset;
+ canvasBoundingRect.width = element.width;
+ canvasBoundingRect.height = element.height;
+ }
+ else {
+ canvasBoundingRect.left = leftOffset;
+ canvasBoundingRect.top = topOffset;
+ canvasBoundingRect.width = parseInt(element.style.width);
+ canvasBoundingRect.height = parseInt(element.style.height);
+ }
+ },
+
/**
* @method handleTouchesBegin
* @param {Array} touches
@@ -185,7 +222,7 @@ let inputManager = {
if (handleTouches.length > 0) {
this._glView._convertTouchesWithScale(handleTouches);
let touchEvent = new cc.Event.EventTouch(handleTouches);
- touchEvent._eventCode = cc.Event.EventTouch.CANCELLED;
+ touchEvent._eventCode = cc.Event.EventTouch.CANCELED;
eventManager.dispatchEvent(touchEvent);
}
this._preTouchPool.length = 0;
@@ -217,53 +254,6 @@ let inputManager = {
return handleTouches;
},
- /**
- * @method getHTMLElementPosition
- * @param {HTMLElement} element
- * @return {Object}
- */
- getHTMLElementPosition (element) {
- if (sys.platform === sys.WECHAT_GAME) {
- return {
- left: 0,
- top: 0,
- width: window.innerWidth,
- height: window.innerHeight
- };
- }
-
- let docElem = document.documentElement;
- let leftOffset = window.pageXOffset - docElem.clientLeft;
- let topOffset = window.pageYOffset - docElem.clientTop;
- if (element.getBoundingClientRect) {
- let box = element.getBoundingClientRect();
- return {
- left: box.left + leftOffset,
- top: box.top + topOffset,
- width: box.width,
- height: box.height
- };
- }
- else {
- if (element instanceof HTMLCanvasElement) {
- return {
- left: leftOffset,
- top: topOffset,
- width: element.width,
- height: element.height
- };
- }
- else {
- return {
- left: leftOffset,
- top: topOffset,
- width: parseInt(element.style.width),
- height: parseInt(element.style.height)
- };
- }
- }
- },
-
/**
* @method getPreTouch
* @param {Touch} touch
@@ -319,7 +309,7 @@ let inputManager = {
getTouchByXY (tx, ty, pos) {
let locPreTouch = this._preTouchPoint;
let location = this._glView.convertToLocationInView(tx, ty, pos);
- let touch = new cc.Touch(location.x, location.y, 0);
+ let touch = new cc.Touch(location.x, location.y, 0);
touch._setPrevPoint(locPreTouch.x, locPreTouch.y);
locPreTouch.x = location.x;
locPreTouch.y = location.y;
@@ -351,17 +341,19 @@ let inputManager = {
* @return {Vec2}
*/
getPointByEvent (event, pos) {
+ // qq , uc and safari browser can't calculate pageY correctly, need to refresh canvas bounding rect
+ if (cc.sys.browserType === cc.sys.BROWSER_TYPE_QQ
+ || cc.sys.browserType === cc.sys.BROWSER_TYPE_UC
+ || cc.sys.browserType === cc.sys.BROWSER_TYPE_SAFARI) {
+ this._updateCanvasBoundingRect();
+ }
+
if (event.pageX != null) //not avalable in <= IE8
return {x: event.pageX, y: event.pageY};
- if (sys.platform === sys.WECHAT_GAME) {
- pos.left = 0;
- pos.top = 0;
- }
- else {
- pos.left -= document.body.scrollLeft;
- pos.top -= document.body.scrollTop;
- }
+ pos.left -= document.body.scrollLeft;
+ pos.top -= document.body.scrollTop;
+
return {x: event.clientX, y: event.clientY};
},
@@ -412,17 +404,14 @@ let inputManager = {
this._glView = cc.view;
let selfPointer = this;
+ let canvasBoundingRect = this._canvasBoundingRect;
+
+ window.addEventListener('resize', this._updateCanvasBoundingRect.bind(this));
let prohibition = sys.isMobile;
let supportMouse = ('mouse' in sys.capabilities);
let supportTouches = ('touches' in sys.capabilities);
- if (sys.platform === sys.WECHAT_GAME) {
- prohibition = false;
- supportTouches = true;
- supportMouse = false;
- }
-
if (supportMouse) {
//HACK
// - At the same time to trigger the ontouch event and onmouse event
@@ -442,12 +431,11 @@ let inputManager = {
selfPointer._mousePressed = false;
- let pos = selfPointer.getHTMLElementPosition(element);
- let location = selfPointer.getPointByEvent(event, pos);
- if (!cc.rect(pos.left, pos.top, pos.width, pos.height).contains(location)){
- selfPointer.handleTouchesEnd([selfPointer.getTouchByXY(location.x, location.y, pos)]);
+ let location = selfPointer.getPointByEvent(event, canvasBoundingRect);
+ if (!cc.rect(canvasBoundingRect.left, canvasBoundingRect.top, canvasBoundingRect.width, canvasBoundingRect.height).contains(location)){
+ selfPointer.handleTouchesEnd([selfPointer.getTouchByXY(location.x, location.y, canvasBoundingRect)]);
- let mouseEvent = selfPointer.getMouseEvent(location,pos,cc.Event.EventMouse.UP);
+ let mouseEvent = selfPointer.getMouseEvent(location, canvasBoundingRect, cc.Event.EventMouse.UP);
mouseEvent.setButton(event.button);
eventManager.dispatchEvent(mouseEvent);
}
@@ -457,17 +445,17 @@ let inputManager = {
// register canvas mouse event
let EventMouse = cc.Event.EventMouse;
let _mouseEventsOnElement = [
- !prohibition && ["mousedown", EventMouse.DOWN, function (event, mouseEvent, location, pos) {
+ !prohibition && ["mousedown", EventMouse.DOWN, function (event, mouseEvent, location, canvasBoundingRect) {
selfPointer._mousePressed = true;
- selfPointer.handleTouchesBegin([selfPointer.getTouchByXY(location.x, location.y, pos)]);
+ selfPointer.handleTouchesBegin([selfPointer.getTouchByXY(location.x, location.y, canvasBoundingRect)]);
element.focus();
}],
- !prohibition && ["mouseup", EventMouse.UP, function (event, mouseEvent, location, pos) {
+ !prohibition && ["mouseup", EventMouse.UP, function (event, mouseEvent, location, canvasBoundingRect) {
selfPointer._mousePressed = false;
- selfPointer.handleTouchesEnd([selfPointer.getTouchByXY(location.x, location.y, pos)]);
+ selfPointer.handleTouchesEnd([selfPointer.getTouchByXY(location.x, location.y, canvasBoundingRect)]);
}],
- !prohibition && ["mousemove", EventMouse.MOVE, function (event, mouseEvent, location, pos) {
- selfPointer.handleTouchesMove([selfPointer.getTouchByXY(location.x, location.y, pos)]);
+ !prohibition && ["mousemove", EventMouse.MOVE, function (event, mouseEvent, location, canvasBoundingRect) {
+ selfPointer.handleTouchesMove([selfPointer.getTouchByXY(location.x, location.y, canvasBoundingRect)]);
if (!selfPointer._mousePressed) {
mouseEvent.setButton(null);
}
@@ -487,12 +475,11 @@ let inputManager = {
let type = entry[1];
let handler = entry[2];
element.addEventListener(name, function (event) {
- let pos = selfPointer.getHTMLElementPosition(element);
- let location = selfPointer.getPointByEvent(event, pos);
- let mouseEvent = selfPointer.getMouseEvent(location, pos, type);
+ let location = selfPointer.getPointByEvent(event, canvasBoundingRect);
+ let mouseEvent = selfPointer.getMouseEvent(location, canvasBoundingRect, type);
mouseEvent.setButton(event.button);
- handler(event, mouseEvent, location, pos);
+ handler(event, mouseEvent, location, canvasBoundingRect);
eventManager.dispatchEvent(mouseEvent);
event.stopPropagation();
@@ -512,11 +499,11 @@ let inputManager = {
for (let eventName in _pointerEventsMap) {
let touchEvent = _pointerEventsMap[eventName];
element.addEventListener(eventName, function (event){
- let pos = selfPointer.getHTMLElementPosition(element);
- pos.left -= document.documentElement.scrollLeft;
- pos.top -= document.documentElement.scrollTop;
+ let documentElement = document.documentElement;
+ canvasBoundingRect.adjustedLeft = canvasBoundingRect.left - documentElement.scrollLeft;
+ canvasBoundingRect.adjustedTop = canvasBoundingRect.top - documentElement.scrollTop;
- touchEvent.call(selfPointer, [selfPointer.getTouchByXY(event.clientX, event.clientY, pos)]);
+ touchEvent.call(selfPointer, [selfPointer.getTouchByXY(event.clientX, event.clientY, canvasBoundingRect)]);
event.stopPropagation();
}, false);
}
@@ -527,9 +514,7 @@ let inputManager = {
let _touchEventsMap = {
"touchstart": function (touchesToHandle) {
selfPointer.handleTouchesBegin(touchesToHandle);
- if (sys.platform !== sys.WECHAT_GAME) {
- element.focus();
- }
+ element.focus();
},
"touchmove": function (touchesToHandle) {
selfPointer.handleTouchesMove(touchesToHandle);
@@ -542,50 +527,25 @@ let inputManager = {
}
};
- let registerTouchEvent;
- if (cc.sys.browserType === cc.sys.BROWSER_TYPE_WECHAT_GAME_SUB) {
- _touchEventsMap = {
- onTouchStart: _touchEventsMap.touchstart,
- onTouchMove: _touchEventsMap.touchmove,
- onTouchEnd: _touchEventsMap.touchend,
- onTouchCancel: _touchEventsMap.touchcancel,
- };
- registerTouchEvent = function(eventName) {
- let handler = _touchEventsMap[eventName];
- wx[eventName](function(event) {
- if (!event.changedTouches) return;
- let pos = selfPointer.getHTMLElementPosition(element);
- let body = document.body;
- pos.left -= body.scrollLeft || 0;
- pos.top -= body.scrollTop || 0;
- handler(selfPointer.getTouchesByEvent(event, pos));
- });
- };
- }
- else {
- registerTouchEvent = function(eventName) {
- let handler = _touchEventsMap[eventName];
- element.addEventListener(eventName, (function(event) {
- if (!event.changedTouches) return;
- let pos = selfPointer.getHTMLElementPosition(element);
- let body = document.body;
- pos.left -= body.scrollLeft || 0;
- pos.top -= body.scrollTop || 0;
- handler(selfPointer.getTouchesByEvent(event, pos));
- event.stopPropagation();
- event.preventDefault();
- }), false);
- };
- }
+ let registerTouchEvent = function (eventName) {
+ let handler = _touchEventsMap[eventName];
+ element.addEventListener(eventName, (function(event) {
+ if (!event.changedTouches) return;
+ let body = document.body;
+
+ canvasBoundingRect.adjustedLeft = canvasBoundingRect.left - (body.scrollLeft || window.scrollX || 0);
+ canvasBoundingRect.adjustedTop = canvasBoundingRect.top - (body.scrollTop || window.scrollY || 0);
+ handler(selfPointer.getTouchesByEvent(event, canvasBoundingRect));
+ event.stopPropagation();
+ event.preventDefault();
+ }), false);
+ };
for (let eventName in _touchEventsMap) {
registerTouchEvent(eventName);
}
}
- if (cc.sys.browserType !== cc.sys.BROWSER_TYPE_WECHAT_GAME_SUB) {
- //register keyboard event
- this._registerKeyboardEvent();
- }
+ this._registerKeyboardEvent();
this._isRegisterEvent = true;
},
@@ -607,4 +567,4 @@ let inputManager = {
}
};
-module.exports = _cc.inputManager = inputManager;
+module.exports = cc.internal.inputManager = inputManager;
diff --git a/cocos2d/core/platform/CCMacro.js b/cocos2d/core/platform/CCMacro.js
index ffbc1865291..dddc6861b50 100644
--- a/cocos2d/core/platform/CCMacro.js
+++ b/cocos2d/core/platform/CCMacro.js
@@ -25,8 +25,6 @@
THE SOFTWARE.
****************************************************************************/
-const js = require('./js');
-
/**
* Predefined constants
* @class macro
@@ -255,22 +253,12 @@ cc.macro = {
* !#en
* Whether or not enabled tiled map auto culling. If you set the TiledMap skew or rotation, then need to manually disable this, otherwise, the rendering will be wrong.
* !#zh
- * 是否开启瓦片地图的自动裁减功能。瓦片地图如果设置了 skew, rotation 的话,需要手动关闭,否则渲染会出错。
+ * 是否开启瓦片地图的自动裁减功能。瓦片地图如果设置了 skew, rotation 或者采用了摄像机的话,需要手动关闭,否则渲染会出错。
* @property {Boolean} ENABLE_TILEDMAP_CULLING
* @default true
*/
ENABLE_TILEDMAP_CULLING: true,
- /**
- * !#en
- * The max concurrent task number for the downloader
- * !#zh
- * 下载任务的最大并发数限制,在安卓平台部分机型或版本上可能需要限制在较低的水平
- * @property {Number} DOWNLOAD_MAX_CONCURRENT
- * @default 64
- */
- DOWNLOAD_MAX_CONCURRENT: 64,
-
/**
* !#en
* Boolean that indicates if the canvas contains an alpha channel, default sets to false for better performance.
@@ -328,15 +316,13 @@ cc.macro = {
/**
* !#en
- * Whether or not clear dom Image object cache after uploading to gl texture.
- * Concretely, we are setting image.src to empty string to release the cache.
- * Normally you don't need to enable this option, because on web the Image object doesn't consume too much memory.
- * But on Wechat Game platform, the current version cache decoded data in Image object, which has high memory usage.
- * So we enabled this option by default on Wechat, so that we can release Image cache immediately after uploaded to GPU.
+ * Whether to clear the original image cache after uploaded a texture to GPU. If cleared, [Dynamic Atlas](https://docs.cocos.com/creator/manual/en/advanced-topics/dynamic-atlas.html) will not be supported.
+ * Normally you don't need to enable this option on the web platform, because Image object doesn't consume too much memory.
+ * But on WeChat Game platform, the current version cache decoded data in Image object, which has high memory usage.
+ * So we enabled this option by default on WeChat, so that we can release Image cache immediately after uploaded to GPU.
* !#zh
- * 是否在将贴图上传至 GPU 之后删除 DOM Image 缓存。
- * 具体来说,我们通过设置 image.src 为空字符串来释放这部分内存。
- * 正常情况下,你不需要开启这个选项,因为在 web 平台,Image 对象所占用的内存很小。
+ * 是否在将贴图上传至 GPU 之后删除原始图片缓存,删除之后图片将无法进行 [动态合图](https://docs.cocos.com/creator/manual/zh/advanced-topics/dynamic-atlas.html)。
+ * 在 Web 平台,你通常不需要开启这个选项,因为在 Web 平台 Image 对象所占用的内存很小。
* 但是在微信小游戏平台的当前版本,Image 对象会缓存解码后的图片数据,它所占用的内存空间很大。
* 所以我们在微信平台默认开启了这个选项,这样我们就可以在上传 GL 贴图之后立即释放 Image 对象的内存,避免过高的内存占用。
* @property {Boolean} CLEANUP_IMAGE_CACHE
@@ -353,27 +339,75 @@ cc.macro = {
* @default false
*/
SHOW_MESH_WIREFRAME: false,
-};
+ /**
+ * !#en
+ * Whether or not show mesh normal.
+ * !#zh
+ * 是否显示网格的法线。
+ * @property {Boolean} SHOW_MESH_NORMAL
+ * @default false
+ */
+ SHOW_MESH_NORMAL: false,
+
+ /**
+ * !#en
+ * Whether to enable multi-touch.
+ * !#zh
+ * 是否开启多点触摸
+ * @property {Boolean} ENABLE_MULTI_TOUCH
+ * @default true
+ */
+ ENABLE_MULTI_TOUCH: true,
+
+ /**
+ * References:
+ * https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap
+ * https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/createImageBitmap
+ *
+ * !#en
+ * Whether to use image bitmap first. If enabled, memory usage will increase.
+ *
+ * !#zh
+ * 是否优先使用 image bitmap,启用之后,内存占用会变高
+ *
+ * @property {Boolean} ALLOW_IMAGE_BITMAP
+ * @default true
+ */
+ ALLOW_IMAGE_BITMAP: !cc.sys.isMobile,
+
+ /**
+ * !#en
+ * Whether to use native TTF renderer which is faster but layout slightly different.
+ *
+ * !#zh
+ * 是否使用原生的文本渲染机制, 布局和编辑器有差异.
+ *
+ * @property {Boolean} ENABLE_NATIVE_TTF_RENDERER
+ * @default true
+ */
+ ENABLE_NATIVE_TTF_RENDERER: true
+
+};
-let SUPPORT_TEXTURE_FORMATS = ['.webp', '.jpg', '.jpeg', '.bmp', '.png'];
-if (cc.sys.isMobile) {
- if (cc.sys.os === cc.sys.OS_IOS) {
- SUPPORT_TEXTURE_FORMATS = ['.pvr'].concat(SUPPORT_TEXTURE_FORMATS);
+Object.defineProperty(cc.macro, 'ROTATE_ACTION_CCW', {
+ set (value) {
+ if (cc.RotateTo && cc.RotateBy) {
+ cc.RotateTo._reverse = cc.RotateBy._reverse = value;
+ }
}
- // else if (cc.sys.os === cc.sys.OS_ANDROID) {
- // SUPPORT_TEXTURE_FORMATS = ['.etc'].join(SUPPORT_TEXTURE_FORMATS);
- // }
-}
+});
+
+let SUPPORT_TEXTURE_FORMATS = ['.pkm', '.pvr', '.webp', '.jpg', '.jpeg', '.bmp', '.png'];
/**
- * !en
+ * !#en
* The image format supported by the engine defaults, and the supported formats may differ in different build platforms and device types.
- * Currently all platform and device support ['.webp', '.jpg', '.jpeg', '.bmp', '.png'], ios mobile platform
- * !zh
+ * Currently all platform and device support ['.webp', '.jpg', '.jpeg', '.bmp', '.png'], The iOS mobile platform also supports the PVR format。
+ * !#zh
* 引擎默认支持的图片格式,支持的格式可能在不同的构建平台和设备类型上有所差别。
- * 目前所有平台和设备支持的格式有 ['.webp', '.jpg', '.jpeg', '.bmp', '.png']. The iOS mobile platform also supports the PVR format。
- * @property {[String]} SUPPORT_TEXTURE_FORMATS
+ * 目前所有平台和设备支持的格式有 ['.webp', '.jpg', '.jpeg', '.bmp', '.png']. 另外 Ios 手机平台还额外支持了 PVR 格式。
+ * @property {String[]} SUPPORT_TEXTURE_FORMATS
*/
cc.macro.SUPPORT_TEXTURE_FORMATS = SUPPORT_TEXTURE_FORMATS;
diff --git a/cocos2d/core/platform/CCObject.js b/cocos2d/core/platform/CCObject.js
index 37eb6dddbcf..ad5447f1a2f 100644
--- a/cocos2d/core/platform/CCObject.js
+++ b/cocos2d/core/platform/CCObject.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -39,7 +39,7 @@ var Destroying = 1 << 7;
var Deactivating = 1 << 8;
var LockedInEditor = 1 << 9;
//var HideInGame = 1 << 9;
-//var HideInEditor = 1 << 10;
+var HideInHierarchy = 1 << 10;
var IsOnEnableCalled = 1 << 11;
var IsEditorOnEnableCalled = 1 << 12;
@@ -54,7 +54,7 @@ var IsAnchorLocked = 1 << 19;
var IsSizeLocked = 1 << 20;
var IsPositionLocked = 1 << 21;
-//var Hide = HideInGame | HideInEditor;
+// var Hide = HideInGame | HideInHierarchy;
// should not clone or serialize these flags
var PersistentMask = ~(ToDestroy | Dirty | Destroying | DontDestroy | Deactivating |
IsPreloadStarted | IsOnLoadStarted | IsOnLoadCalled | IsStartCalled |
@@ -115,7 +115,7 @@ js.value(CCObject, 'Flags', {
/**
* !#en Dont destroy automatically when loading a new scene.
- * !#zh 加载一个新场景时,不自动删除该对象
+ * !#zh 加载一个新场景时,不自动删除该对象。
* @property DontDestroy
* @private
*/
@@ -137,7 +137,7 @@ js.value(CCObject, 'Flags', {
/**
* !#en The lock node, when the node is locked, cannot be clicked in the scene.
- * !#zh 锁定节点,锁定后场景内不能点击
+ * !#zh 锁定节点,锁定后场景内不能点击。
*
* @property LockedInEditor
* @private
@@ -147,37 +147,34 @@ js.value(CCObject, 'Flags', {
///**
// * !#en
// * Hide in game and hierarchy.
- // * This flag is readonly, it can only be used as an argument of scene.addEntity() or Entity.createWithFlags().
+ // * This flag is readonly, it can only be used as an argument of `scene.addEntity()` or `Entity.createWithFlags()`.
// * !#zh
// * 在游戏和层级中隐藏该对象。
- // * 该标记只读,它只能被用作 scene.addEntity()的一个参数。
+ // * 该标记只读,它只能被用作 `scene.addEntity()` 或者 `Entity.createWithFlags()` 的一个参数。
// * @property {Number} HideInGame
// */
//HideInGame: HideInGame,
// FLAGS FOR EDITOR
- ///**
- // * !#en This flag is readonly, it can only be used as an argument of scene.addEntity() or Entity.createWithFlags().
- // * !#zh 该标记只读,它只能被用作 scene.addEntity()的一个参数。
- // * @property {Number} HideInEditor
- // */
- //HideInEditor: HideInEditor,
+ /**
+ * !#en Hide the object in editor.
+ * !#zh 在编辑器中隐藏该对象。
+ * @property {Number} HideInHierarchy
+ */
+ HideInHierarchy: HideInHierarchy,
///**
// * !#en
// * Hide in game view, hierarchy, and scene view... etc.
- // * This flag is readonly, it can only be used as an argument of scene.addEntity() or Entity.createWithFlags().
+ // * This flag is readonly, it can only be used as an argument of `scene.addEntity()` or `Entity.createWithFlags()`.
// * !#zh
// * 在游戏视图,层级,场景视图等等...中隐藏该对象。
- // * 该标记只读,它只能被用作 scene.addEntity()的一个参数。
+ // * 该标记只读,它只能被用作 `scene.addEntity()` 或者 `Entity.createWithFlags()` 的一个参数。
// * @property {Number} Hide
// */
//Hide: Hide,
- //// UUID Registered in editor
- //RegisteredInEditor: RegisteredInEditor,
-
// FLAGS FOR COMPONENT
IsPreloadStarted,
@@ -294,12 +291,12 @@ var deferredDestroyTimer = null;
* !#en
* Destroy this Object, and release all its own references to other objects.
* Actual object destruction will delayed until before rendering.
- * From the next frame, this object is not usable any more.
- * You can use cc.isValid(obj) to check whether the object is destroyed before accessing it.
+ * From the next frame, this object is not usable anymore.
+ * You can use `cc.isValid(obj)` to check whether the object is destroyed before accessing it.
* !#zh
* 销毁该对象,并释放所有它对其它对象的引用。
* 实际销毁操作会延迟到当前帧渲染前执行。从下一帧开始,该对象将不再可用。
- * 您可以在访问对象之前使用 cc.isValid(obj) 来检查对象是否已被销毁。
+ * 您可以在访问对象之前使用 `cc.isValid(obj)` 来检查对象是否已被销毁。
* @method destroy
* @return {Boolean} whether it is the first time the destroy being called
* @example
@@ -330,7 +327,7 @@ if (CC_EDITOR || CC_TEST) {
* The destruct operation will be executed by Undo system later.
* !#zh
* 事实上,对象的 “destroy” 不会在编辑器中触发析构操作,
- * 析构操作将在 Undo 系统中**延后**执行。
+ * 析构操作将在 Undo 系统中 **延后** 执行。
* @method realDestroyInEditor
* @private
*/
@@ -425,25 +422,48 @@ function compileDestruct (obj, ctor) {
}
/**
+ * !#en
* Clear all references in the instance.
*
- * NOTE: this method will not clear the getter or setter functions which defined in the instance of CCObject.
- * You can override the _destruct method if you need, for example:
- * _destruct: function () {
- * for (var key in this) {
- * if (this.hasOwnProperty(key)) {
- * switch (typeof this[key]) {
- * case 'string':
- * this[key] = '';
- * break;
- * case 'object':
- * case 'function':
- * this[key] = null;
- * break;
- * }
- * }
- * }
- *
+ * NOTE: this method will not clear the `getter` or `setter` functions which defined in the instance of `CCObject`.
+ * You can override the `_destruct` method if you need, for example:
+ * ```js
+ * _destruct: function () {
+ * for (var key in this) {
+ * if (this.hasOwnProperty(key)) {
+ * switch (typeof this[key]) {
+ * case 'string':
+ * this[key] = '';
+ * break;
+ * case 'object':
+ * case 'function':
+ * this[key] = null;
+ * break;
+ * }
+ * }
+ * }
+ * ```
+ * !#zh
+ * 清除实例中的所有引用。
+ *
+ * 注意:此方法不会清除在 `CCObject` 实例中定义的 `getter` 或 `setter`。如果需要,你可以重写 `_destruct` 方法。例如:
+ *
+ * ```js
+ * _destruct: function () {
+ * for (var key in this) {
+ * if (this.hasOwnProperty(key)) {
+ * switch (typeof this[key]) {
+ * case 'string':
+ * this[key] = '';
+ * break;
+ * case 'object':
+ * case 'function':
+ * this[key] = null;
+ * break;
+ * }
+ * }
+ * }
+ * ```
* @method _destruct
* @private
*/
@@ -458,7 +478,10 @@ prototype._destruct = function () {
};
/**
+ * !#en
* Called before the object being destroyed.
+ * !#zh
+ * 在对象被销毁之前调用。
* @method _onPreDestroy
* @private
*/
@@ -483,7 +506,10 @@ prototype._destroyImmediate = function () {
if (CC_EDITOR) {
/**
+ * !#en
* The customized serialization for this object. (Editor Only)
+ * !#zh
+ * 为此对象定制序列化。
* @method _serialize
* @param {Boolean} exporting
* @return {object} the serialized json data object
@@ -493,7 +519,10 @@ if (CC_EDITOR) {
}
/**
+ * !#en
* Init this object from the custom serialized data.
+ * !#zh
+ * 从自定义序列化数据初始化此对象。
* @method _deserialize
* @param {Object} data - the serialized json data
* @param {_Deserializer} ctx
diff --git a/cocos2d/core/platform/CCScreen.js b/cocos2d/core/platform/CCScreen.js
index 553c18bdf93..f8cd10973a5 100644
--- a/cocos2d/core/platform/CCScreen.js
+++ b/cocos2d/core/platform/CCScreen.js
@@ -32,8 +32,12 @@
*/
cc.screen = /** @lends cc.screen# */{
_supportsFullScreen: false,
+ _onfullscreenchange: null,
+ _onfullscreenerror: null,
// the pre fullscreenchange function
_preOnFullScreenChange: null,
+ _preOnFullScreenError: null,
+ _preOnTouch: null,
_touchEvent: "",
_fn: null,
// Function mapping for cross browser support
@@ -43,35 +47,40 @@ cc.screen = /** @lends cc.screen# */{
'exitFullscreen',
'fullscreenchange',
'fullscreenEnabled',
- 'fullscreenElement'
+ 'fullscreenElement',
+ 'fullscreenerror',
],
[
'requestFullScreen',
'exitFullScreen',
'fullScreenchange',
'fullScreenEnabled',
- 'fullScreenElement'
+ 'fullScreenElement',
+ 'fullscreenerror',
],
[
'webkitRequestFullScreen',
'webkitCancelFullScreen',
'webkitfullscreenchange',
'webkitIsFullScreen',
- 'webkitCurrentFullScreenElement'
+ 'webkitCurrentFullScreenElement',
+ 'webkitfullscreenerror',
],
[
'mozRequestFullScreen',
'mozCancelFullScreen',
'mozfullscreenchange',
'mozFullScreen',
- 'mozFullScreenElement'
+ 'mozFullScreenElement',
+ 'mozfullscreenerror',
],
[
'msRequestFullscreen',
'msExitFullscreen',
'MSFullscreenChange',
'msFullscreenEnabled',
- 'msFullscreenElement'
+ 'msFullscreenElement',
+ 'msfullscreenerror',
]
],
@@ -93,7 +102,11 @@ cc.screen = /** @lends cc.screen# */{
}
this._supportsFullScreen = (this._fn.requestFullscreen !== undefined);
- this._touchEvent = ('ontouchstart' in window) ? 'touchstart' : 'mousedown';
+
+ // Bug fix only for v2.1, don't merge into v2.0
+ // In v2.0, screen touchend events conflict with editBox touchend events if it's not stayOnTop.
+ // While in v2.1, editBox always keep stayOnTop and it doesn't support touchend events.
+ this._touchEvent = ('ontouchend' in window) ? 'touchend' : 'mousedown';
},
/**
@@ -102,11 +115,13 @@ cc.screen = /** @lends cc.screen# */{
* @returns {Boolean}
*/
fullScreen: function () {
- if(!this._supportsFullScreen) return false;
- else if( document[this._fn.fullscreenElement] === undefined || document[this._fn.fullscreenElement] === null )
+ if (!this._supportsFullScreen) return false;
+ else if (!document[this._fn.fullscreenElement] && !document[this._fn.webkitFullscreenElement] && !document[this._fn.mozFullScreenElement]) {
return false;
- else
+ }
+ else {
return true;
+ }
},
/**
@@ -114,8 +129,19 @@ cc.screen = /** @lends cc.screen# */{
* @method requestFullScreen
* @param {Element} element
* @param {Function} onFullScreenChange
+ * @param {Function} onFullScreenError
*/
- requestFullScreen: function (element, onFullScreenChange) {
+ requestFullScreen: function (element, onFullScreenChange, onFullScreenError) {
+ if (element && element.tagName.toLowerCase() === "video") {
+ if (cc.sys.os === cc.sys.OS_IOS && cc.sys.isBrowser && element.readyState > 0) {
+ element.webkitEnterFullscreen && element.webkitEnterFullscreen();
+ return;
+ }
+ else {
+ element.setAttribute("x5-video-player-fullscreen", "true");
+ }
+ }
+
if (!this._supportsFullScreen) {
return;
}
@@ -123,15 +149,30 @@ cc.screen = /** @lends cc.screen# */{
element = element || document.documentElement;
if (onFullScreenChange) {
- var eventName = this._fn.fullscreenchange;
- if (this._preOnFullScreenChange) {
- document.removeEventListener(eventName, this._preOnFullScreenChange);
+ let eventName = this._fn.fullscreenchange;
+ if (this._onfullscreenchange) {
+ document.removeEventListener(eventName, this._onfullscreenchange);
}
- this._preOnFullScreenChange = onFullScreenChange;
+ this._onfullscreenchange = onFullScreenChange;
document.addEventListener(eventName, onFullScreenChange, false);
}
+ if (onFullScreenError) {
+ let eventName = this._fn.fullscreenerror;
+ if (this._onfullscreenerror) {
+ document.removeEventListener(eventName, this._onfullscreenerror);
+ }
+ this._onfullscreenerror = onFullScreenError;
+ document.addEventListener(eventName, onFullScreenError, { once: true });
+ }
- return element[this._fn.requestFullscreen]();
+ let requestPromise = element[this._fn.requestFullscreen]();
+ // the requestFullscreen API can only be initiated by user gesture.
+ if (typeof document[this._fn.fullscreenerror] === 'undefined'
+ && window.Promise && requestPromise instanceof Promise) {
+ requestPromise.catch(function (err) {
+ // do nothing ...
+ });
+ }
},
/**
@@ -139,7 +180,16 @@ cc.screen = /** @lends cc.screen# */{
* @method exitFullScreen
* @return {Boolean}
*/
- exitFullScreen: function () {
+ exitFullScreen: function (element) {
+ if (element && element.tagName.toLowerCase() === "video") {
+ if (cc.sys.os === cc.sys.OS_IOS && cc.sys.isBrowser) {
+ element.webkitExitFullscreen && element.webkitExitFullscreen();
+ return;
+ }
+ else {
+ element.setAttribute("x5-video-player-fullscreen", "false");
+ }
+ }
return this._supportsFullScreen ? document[this._fn.exitFullscreen]() : true;
},
@@ -151,15 +201,48 @@ cc.screen = /** @lends cc.screen# */{
*/
autoFullScreen: function (element, onFullScreenChange) {
element = element || document.body;
- var touchTarget = cc.game.canvas || element;
- var theScreen = this;
- // Function bind will be too complicated here because we need the callback function's reference to remove the listener
- function callback() {
- touchTarget.removeEventListener(theScreen._touchEvent, callback);
- theScreen.requestFullScreen(element, onFullScreenChange);
- }
+
+ this._ensureFullScreen(element, onFullScreenChange);
this.requestFullScreen(element, onFullScreenChange);
- touchTarget.addEventListener(this._touchEvent, callback);
- }
+ },
+
+ disableAutoFullScreen (element) {
+ let touchTarget = cc.game.canvas || element;
+ let touchEventName = this._touchEvent;
+ if (this._preOnTouch) {
+ touchTarget.removeEventListener(touchEventName, this._preOnTouch);
+ this._preOnTouch = null;
+ }
+ },
+
+ // Register touch event if request full screen failed
+ _ensureFullScreen (element, onFullScreenChange) {
+ let self = this;
+ let touchTarget = cc.game.canvas || element;
+ let fullScreenErrorEventName = this._fn.fullscreenerror;
+ let touchEventName = this._touchEvent;
+
+ function onFullScreenError () {
+ self._preOnFullScreenError = null;
+
+ // handle touch event listener
+ function onTouch() {
+ self._preOnTouch = null;
+ self.requestFullScreen(element, onFullScreenChange);
+ }
+ if (self._preOnTouch) {
+ touchTarget.removeEventListener(touchEventName, self._preOnTouch);
+ }
+ self._preOnTouch = onTouch;
+ touchTarget.addEventListener(touchEventName, self._preOnTouch, { once: true });
+ }
+
+ // handle full screen error
+ if (this._preOnFullScreenError) {
+ element.removeEventListener(fullScreenErrorEventName, this._preOnFullScreenError);
+ }
+ this._preOnFullScreenError = onFullScreenError;
+ element.addEventListener(fullScreenErrorEventName, onFullScreenError, { once: true });
+ },
};
cc.screen.init();
diff --git a/cocos2d/core/platform/CCSys.js b/cocos2d/core/platform/CCSys.js
index 70526fb68cc..8912bedb4ca 100644
--- a/cocos2d/core/platform/CCSys.js
+++ b/cocos2d/core/platform/CCSys.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -24,6 +24,19 @@
THE SOFTWARE.
****************************************************************************/
+let settingPlatform;
+ if (!CC_EDITOR) {
+ settingPlatform = window._CCSettings ? _CCSettings.platform: undefined;
+ }
+const isVivoGame = (settingPlatform === 'qgame');
+const isOppoGame = (settingPlatform === 'quickgame');
+const isHuaweiGame = (settingPlatform === 'huawei');
+const isJKWGame = (settingPlatform === 'jkw-game');
+const isQttGame = (settingPlatform === 'qtt-game');
+const isLinkSure = (settingPlatform === 'link-sure');
+
+const _global = typeof window === 'undefined' ? global : window;
+
function initSys () {
/**
* System variables
@@ -348,33 +361,96 @@ function initSys () {
*/
sys.QQ_PLAY = 105;
/**
- * BROWSER_TYPE_WECHAT
- * @property {String} BROWSER_TYPE_WECHAT
+ * @property {Number} FB_PLAYABLE_ADS
* @readOnly
- * @default "wechat"
+ * @default 106
*/
- sys.BROWSER_TYPE_WECHAT = "wechat";
+ sys.FB_PLAYABLE_ADS = 106;
+ /**
+ * @property {Number} BAIDU_GAME
+ * @readOnly
+ * @default 107
+ */
+ sys.BAIDU_GAME = 107;
+ /**
+ * @property {Number} VIVO_GAME
+ * @readOnly
+ * @default 108
+ */
+ sys.VIVO_GAME = 108;
+ /**
+ * @property {Number} OPPO_GAME
+ * @readOnly
+ * @default 109
+ */
+ sys.OPPO_GAME = 109;
+ /**
+ * @property {Number} HUAWEI_GAME
+ * @readOnly
+ * @default 110
+ */
+ sys.HUAWEI_GAME = 110;
+ /**
+ * @property {Number} XIAOMI_GAME
+ * @readOnly
+ * @default 111
+ */
+ sys.XIAOMI_GAME = 111;
/**
- * BROWSER_TYPE_WECHAT_GAME
- * @property {String} BROWSER_TYPE_WECHAT_GAME
+ * @property {Number} JKW_GAME
* @readOnly
- * @default "wechatgame"
+ * @default 112
*/
- sys.BROWSER_TYPE_WECHAT_GAME = "wechatgame";
+ sys.JKW_GAME = 112;
/**
- * BROWSER_TYPE_WECHAT_GAME_SUB
- * @property {String} BROWSER_TYPE_WECHAT_GAME_SUB
+ * @property {Number} ALIPAY_GAME
* @readOnly
- * @default "wechatgamesub"
+ * @default 113
*/
- sys.BROWSER_TYPE_WECHAT_GAME_SUB = "wechatgamesub";
+ sys.ALIPAY_GAME = 113;
/**
- * BROWSER_TYPE_QQ_PLAY
- * @property {String} BROWSER_TYPE_QQ_PLAY
+ * @property {Number} WECHAT_GAME_SUB
* @readOnly
- * @default "qqplay"
+ * @default 114
*/
- sys.BROWSER_TYPE_QQ_PLAY = "qqplay";
+ sys.WECHAT_GAME_SUB = 114;
+ /**
+ * @property {Number} BAIDU_GAME_SUB
+ * @readOnly
+ * @default 115
+ */
+ sys.BAIDU_GAME_SUB = 115;
+ /**
+ * @property {Number} QTT_GAME
+ * @readOnly
+ * @default 116
+ */
+ sys.QTT_GAME = 116;
+ /**
+ * @property {Number} BYTEDANCE_GAME
+ * @readOnly
+ * @default 117
+ */
+ sys.BYTEDANCE_GAME = 117;
+ /**
+ * @property {Number} BYTEDANCE_GAME_SUB
+ * @readOnly
+ * @default 118
+ */
+ sys.BYTEDANCE_GAME_SUB = 118;
+ /**
+ * @property {Number} LINKSURE
+ * @readOnly
+ * @default 119
+ */
+ sys.LINKSURE = 119;
+ /**
+ * BROWSER_TYPE_WECHAT
+ * @property {String} BROWSER_TYPE_WECHAT
+ * @readOnly
+ * @default "wechat"
+ */
+ sys.BROWSER_TYPE_WECHAT = "wechat";
/**
*
* @property {String} BROWSER_TYPE_ANDROID
@@ -389,6 +465,13 @@ function initSys () {
* @default "ie"
*/
sys.BROWSER_TYPE_IE = "ie";
+ /**
+ *
+ * @property {String} BROWSER_TYPE_EDGE
+ * @readOnly
+ * @default "edge"
+ */
+ sys.BROWSER_TYPE_EDGE = "edge";
/**
*
* @property {String} BROWSER_TYPE_QQ
@@ -508,6 +591,13 @@ function initSys () {
* @default "sogou"
*/
sys.BROWSER_TYPE_SOUGOU = "sogou";
+ /**
+ *
+ * @property {String} BROWSER_TYPE_HUAWEI
+ * @readOnly
+ * @default "huawei"
+ */
+ sys.BROWSER_TYPE_HUAWEI = "huawei";
/**
*
* @property {String} BROWSER_TYPE_UNKNOWN
@@ -520,19 +610,67 @@ function initSys () {
* Is native ? This is set to be true in jsb auto.
* @property {Boolean} isNative
*/
- sys.isNative = CC_JSB;
-
+ sys.isNative = CC_JSB || CC_RUNTIME;
/**
* Is web browser ?
* @property {Boolean} isBrowser
*/
- sys.isBrowser = typeof window === 'object' && typeof document === 'object' && !CC_WECHATGAME && !CC_QQPLAY && !CC_JSB;
+ sys.isBrowser = typeof window === 'object' && typeof document === 'object' && !CC_JSB && !CC_RUNTIME;
+
+ /**
+ * Is webgl extension support?
+ * @method glExtension
+ * @param name
+ */
+ sys.glExtension = function (name) {
+ return !!cc.renderer.device.ext(name);
+ }
+
+ /**
+ * Get max joint matrix size for skinned mesh renderer.
+ * @method getMaxJointMatrixSize
+ */
+ sys.getMaxJointMatrixSize = function () {
+ if (!sys._maxJointMatrixSize) {
+ const JOINT_MATRICES_SIZE = 50;
+ const LEFT_UNIFORM_SIZE = 10;
+
+ let gl = cc.game._renderContext;
+ let maxUniforms = Math.floor(gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS) / 4) - LEFT_UNIFORM_SIZE;
+ if (maxUniforms < JOINT_MATRICES_SIZE) {
+ sys._maxJointMatrixSize = 0;
+ }
+ else {
+ sys._maxJointMatrixSize = JOINT_MATRICES_SIZE;
+ }
+ }
+ return sys._maxJointMatrixSize;
+ }
+
+ /**
+ * !#en
+ * Returns the safe area of the screen. If the screen is not notched, the design resolution will be returned by default.
+ * Only supported on Android, iOS and WeChat Mini Game platform.
+ * !#zh
+ * 返回手机屏幕安全区域,如果不是异形屏将默认返回设计分辨率尺寸。目前只支持安卓、iOS 原生平台和微信小游戏平台。
+ * @method getSafeAreaRect
+ * @return {Rect}
+ */
+ sys.getSafeAreaRect = function () {
+ let visibleSize = cc.view.getVisibleSize();
+ return cc.rect(0, 0, visibleSize.width, visibleSize.height);
+ };
- if (CC_EDITOR && Editor.isMainProcess) {
+ if (_global.__globalAdapter && _global.__globalAdapter.adaptSys) {
+ // init sys info in adapter
+ _global.__globalAdapter.adaptSys(sys);
+ }
+ else if (CC_EDITOR && Editor.isMainProcess) {
sys.isMobile = false;
sys.platform = sys.EDITOR_CORE;
sys.language = sys.LANGUAGE_UNKNOWN;
+ sys.languageCode = undefined;
sys.os = ({
darwin: sys.OS_OSX,
win32: sys.OS_WINDOWS,
@@ -544,19 +682,50 @@ function initSys () {
width: 0,
height: 0
};
+ sys.capabilities = {
+ 'imageBitmap': false
+ };
sys.__audioSupport = {};
}
- else if (CC_JSB) {
- var platform = sys.platform = __getPlatform();
+ else if (CC_JSB || CC_RUNTIME) {
+ let platform;
+ if (isVivoGame) {
+ platform = sys.VIVO_GAME;
+ } else if (isOppoGame) {
+ platform = sys.OPPO_GAME;
+ } else if (isHuaweiGame) {
+ platform = sys.HUAWEI_GAME;
+ } else if (isJKWGame) {
+ platform = sys.JKW_GAME;
+ } else if (isQttGame) {
+ platform = sys.QTT_GAME;
+ } else if (isLinkSure) {
+ platform = sys.LINKSURE;
+ }
+ else {
+ platform = __getPlatform();
+ }
+ sys.platform = platform;
sys.isMobile = (platform === sys.ANDROID ||
platform === sys.IPAD ||
platform === sys.IPHONE ||
platform === sys.WP8 ||
platform === sys.TIZEN ||
- platform === sys.BLACKBERRY);
+ platform === sys.BLACKBERRY ||
+ platform === sys.XIAOMI_GAME ||
+ isVivoGame ||
+ isOppoGame ||
+ isHuaweiGame ||
+ isJKWGame ||
+ isQttGame);
sys.os = __getOS();
sys.language = __getCurrentLanguage();
+ var languageCode;
+ if (CC_JSB) {
+ languageCode = __getCurrentLanguageCode();
+ }
+ sys.languageCode = languageCode ? languageCode.toLowerCase() : undefined;
sys.osVersion = __getOSVersion();
sys.osMainVersion = parseInt(sys.osVersion);
sys.browserType = null;
@@ -589,108 +758,8 @@ function initSys () {
capabilities["touches"] = false;
}
- sys.__audioSupport = {
- ONLY_ONE: false,
- WEB_AUDIO: false,
- DELAY_CREATE_CTX: false,
- format: ['.mp3']
- };
- }
- else if (CC_WECHATGAME) {
- var env = wx.getSystemInfoSync();
- sys.isMobile = true;
- sys.platform = sys.WECHAT_GAME;
- sys.language = env.language.substr(0, 2);
- var system = env.system.toLowerCase();
- if (env.platform === "android") {
- sys.os = sys.OS_ANDROID;
- }
- else if (env.platform === "ios") {
- sys.os = sys.OS_IOS;
- }
- else if (env.platform === 'devtools') {
- sys.isMobile = false;
- if (system.indexOf('android') > -1) {
- sys.os = sys.OS_ANDROID;
- }
- else if (system.indexOf('ios') > -1) {
- sys.os = sys.OS_IOS;
- }
- }
- // Adaptation to Android P
- if (system === 'android p') {
- system = 'android p 9.0';
- }
+ capabilities['imageBitmap'] = false;
- var version = /[\d\.]+/.exec(system);
- sys.osVersion = version ? version[0] : system;
- sys.osMainVersion = parseInt(sys.osVersion);
- // wechagame subdomain
- if (!wx.getFileSystemManager) {
- sys.browserType = sys.BROWSER_TYPE_WECHAT_GAME_SUB;
- }
- else {
- sys.browserType = sys.BROWSER_TYPE_WECHAT_GAME;
- }
- sys.browserVersion = env.version;
-
- var w = env.windowWidth;
- var h = env.windowHeight;
- var ratio = env.pixelRatio || 1;
- sys.windowPixelResolution = {
- width: ratio * w,
- height: ratio * h
- };
-
- sys.localStorage = window.localStorage;
-
- sys.capabilities = {
- "canvas": true,
- "opengl": (sys.browserType !== sys.BROWSER_TYPE_WECHAT_GAME_SUB),
- "webp": false
- };
- sys.__audioSupport = {
- ONLY_ONE: false,
- WEB_AUDIO: false,
- DELAY_CREATE_CTX: false,
- format: ['.mp3']
- };
- }
- else if (CC_QQPLAY) {
- var env = window["BK"]["Director"]["queryDeviceInfo"]();
- sys.isMobile = true;
- sys.platform = sys.QQ_PLAY;
- sys.language = sys.LANGUAGE_UNKNOWN;
- if (env.platform === "android") {
- sys.os = sys.OS_ANDROID;
- }
- else if (env.platform === "ios") {
- sys.os = sys.OS_IOS;
- }
- else {
- sys.os = sys.OS_UNKNOWN;
- }
- sys.osVersion = env.version;
- sys.osMainVersion = parseInt(sys.osVersion.split('.')[0]);
- sys.browserType = sys.BROWSER_TYPE_QQ_PLAY;
- sys.browserVersion = 0;
-
- var w = env.screenWidth;
- var h = env.screenHeight;
- var ratio = env.pixelRatio || 1;
-
- sys.windowPixelResolution = {
- width: ratio * w,
- height: ratio * h
- };
-
- sys.localStorage = window.localStorage;
-
- sys.capabilities = {
- "canvas": false,
- "opengl": true,
- "webp": false
- };
sys.__audioSupport = {
ONLY_ONE: false,
WEB_AUDIO: false,
@@ -718,11 +787,25 @@ function initSys () {
* Indicate the running platform
* @property {Number} platform
*/
- sys.platform = sys.isMobile ? sys.MOBILE_BROWSER : sys.DESKTOP_BROWSER;
+ if (typeof FbPlayableAd !== "undefined") {
+ sys.platform = sys.FB_PLAYABLE_ADS;
+ }
+ else {
+ sys.platform = sys.isMobile ? sys.MOBILE_BROWSER : sys.DESKTOP_BROWSER;
+ }
}
var currLanguage = nav.language;
currLanguage = currLanguage ? currLanguage : nav.browserLanguage;
+
+ /**
+ * Get current language iso 639-1 code.
+ * Examples of valid language codes include "zh-tw", "en", "en-us", "fr", "fr-fr", "es-es", etc.
+ * The actual value totally depends on results provided by destination platform.
+ * @property {String} languageCode
+ */
+ sys.languageCode = currLanguage.toLowerCase();
+
currLanguage = currLanguage ? currLanguage.split("-")[0] : sys.LANGUAGE_ENGLISH;
/**
@@ -733,7 +816,7 @@ function initSys () {
// Get the os of system
var isAndroid = false, iOS = false, osVersion = '', osMainVersion = 0;
- var uaResult = /android (\d+(?:\.\d+)+)/i.exec(ua) || /android (\d+(?:\.\d+)+)/i.exec(nav.platform);
+ var uaResult = /android\s*(\d+(?:\.\d+)*)/i.exec(ua) || /android\s*(\d+(?:\.\d+)*)/i.exec(nav.platform);
if (uaResult) {
isAndroid = true;
osVersion = uaResult[1] || '';
@@ -745,7 +828,12 @@ function initSys () {
osVersion = uaResult[2] || '';
osMainVersion = parseInt(osVersion) || 0;
}
- else if (/(iPhone|iPad|iPod)/.exec(nav.platform)) {
+ // refer to https://github.com/cocos-creator/engine/pull/5542 , thanks for contribition from @krapnikkk
+ // ipad OS 13 safari identifies itself as "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15 (KHTML, like Gecko)"
+ // so use maxTouchPoints to check whether it's desktop safari or not.
+ // reference: https://stackoverflow.com/questions/58019463/how-to-detect-device-name-in-safari-on-ios-13-while-it-doesnt-show-the-correct
+ // FIXME: should remove it when touch-enabled macs are available
+ else if (/(iPhone|iPad|iPod)/.exec(nav.platform) || (nav.platform === 'MacIntel' && nav.maxTouchPoints && nav.maxTouchPoints > 1)) {
iOS = true;
osVersion = '';
osMainVersion = 0;
@@ -777,50 +865,45 @@ function initSys () {
/**
* Indicate the running browser type
- * @property {String} browserType
+ * @property {String | null} browserType
*/
sys.browserType = sys.BROWSER_TYPE_UNKNOWN;
/* Determine the browser type */
(function(){
- var typeReg1 = /mqqbrowser|micromessenger|qq|sogou|qzone|liebao|maxthon|ucbs|360 aphone|360browser|baiduboxapp|baidubrowser|maxthon|mxbrowser|miuibrowser/i;
- var typeReg2 = /qqbrowser|ucbrowser/i;
+ var typeReg1 = /mqqbrowser|micromessenger|qqbrowser|sogou|qzone|liebao|maxthon|ucbs|360 aphone|360browser|baiduboxapp|baidubrowser|maxthon|mxbrowser|miuibrowser/i;
+ var typeReg2 = /qq|ucbrowser|ubrowser|edge|HuaweiBrowser/i;
var typeReg3 = /chrome|safari|firefox|trident|opera|opr\/|oupeng/i;
- var browserTypes = typeReg1.exec(ua);
- if(!browserTypes) browserTypes = typeReg2.exec(ua);
- if(!browserTypes) browserTypes = typeReg3.exec(ua);
+ var browserTypes = typeReg1.exec(ua) || typeReg2.exec(ua) || typeReg3.exec(ua);
var browserType = browserTypes ? browserTypes[0].toLowerCase() : sys.BROWSER_TYPE_UNKNOWN;
- if (CC_WECHATGAME)
- browserType = sys.BROWSER_TYPE_WECHAT_GAME;
- else if (CC_QQPLAY)
- browserType = sys.BROWSER_TYPE_QQ_PLAY;
- else if (browserType === 'micromessenger')
- browserType = sys.BROWSER_TYPE_WECHAT;
- else if (browserType === "safari" && isAndroid)
+
+ if (browserType === "safari" && isAndroid)
browserType = sys.BROWSER_TYPE_ANDROID;
else if (browserType === "qq" && ua.match(/android.*applewebkit/i))
browserType = sys.BROWSER_TYPE_ANDROID;
- else if (browserType === "trident")
- browserType = sys.BROWSER_TYPE_IE;
- else if (browserType === "360 aphone")
- browserType = sys.BROWSER_TYPE_360;
- else if (browserType === "mxbrowser")
- browserType = sys.BROWSER_TYPE_MAXTHON;
- else if (browserType === "opr/")
- browserType = sys.BROWSER_TYPE_OPERA;
-
- sys.browserType = browserType;
+ let typeMap = {
+ 'micromessenger': sys.BROWSER_TYPE_WECHAT,
+ 'trident': sys.BROWSER_TYPE_IE,
+ 'edge': sys.BROWSER_TYPE_EDGE,
+ '360 aphone': sys.BROWSER_TYPE_360,
+ 'mxbrowser': sys.BROWSER_TYPE_MAXTHON,
+ 'opr/': sys.BROWSER_TYPE_OPERA,
+ 'ubrowser': sys.BROWSER_TYPE_UC,
+ 'huaweibrowser': sys.BROWSER_TYPE_HUAWEI,
+ };
+
+ sys.browserType = typeMap[browserType] || browserType;
})();
/**
* Indicate the running browser version
- * @property {String} browserVersion
+ * @property {String | null} browserVersion
*/
sys.browserVersion = "";
/* Determine the browser version number */
(function(){
- var versionReg1 = /(mqqbrowser|micromessenger|qq|sogou|qzone|liebao|maxthon|uc|ucbs|360 aphone|360|baiduboxapp|baidu|maxthon|mxbrowser|miui)(mobile)?(browser)?\/?([\d.]+)/i;
- var versionReg2 = /(qqbrowser|chrome|safari|firefox|trident|opera|opr\/|oupeng)(mobile)?(browser)?\/?([\d.]+)/i;
+ var versionReg1 = /(mqqbrowser|micromessenger|qqbrowser|sogou|qzone|liebao|maxthon|uc|ucbs|360 aphone|360|baiduboxapp|baidu|maxthon|mxbrowser|miui(?:.hybrid)?)(mobile)?(browser)?\/?([\d.]+)/i;
+ var versionReg2 = /(qq|chrome|safari|firefox|trident|opera|opr\/|oupeng)(mobile)?(browser)?\/?([\d.]+)/i;
var tmp = ua.match(versionReg1);
if(!tmp) tmp = ua.match(versionReg2);
sys.browserVersion = tmp ? tmp[4] : "";
@@ -887,53 +970,11 @@ function initSys () {
var _supportWebp = _tmpCanvas1.toDataURL('image/webp').startsWith('data:image/webp');
var _supportCanvas = !!_tmpCanvas1.getContext("2d");
var _supportWebGL = false;
- if (sys.browserType === sys.BROWSER_TYPE_WECHAT_GAME) {
- _supportWebGL = true;
+ if (CC_TEST) {
+ _supportWebGL = false;
}
else if (win.WebGLRenderingContext) {
- if (create3DContext(document.createElement("CANVAS"))) {
- _supportWebGL = true;
- }
- if (_supportWebGL && sys.os === sys.OS_ANDROID) {
- var browserVer = parseFloat(sys.browserVersion);
- switch (sys.browserType) {
- case sys.BROWSER_TYPE_MOBILE_QQ:
- case sys.BROWSER_TYPE_BAIDU:
- case sys.BROWSER_TYPE_BAIDU_APP:
- // QQ & Baidu Brwoser 6.2+ (using blink kernel)
- if (browserVer >= 6.2) {
- _supportWebGL = true;
- }
- else {
- _supportWebGL = false;
- }
- break;
- case sys.BROWSER_TYPE_ANDROID:
- // Android 5+ default browser
- if (sys.osMainVersion && sys.osMainVersion >= 5) {
- _supportWebGL = true;
- }
- break;
- case sys.BROWSER_TYPE_CHROME:
- // Chrome on android supports WebGL from v. 30
- if (browserVer >= 30.0) {
- _supportWebGL = true;
- } else {
- _supportWebGL = false;
- }
- break;
- case sys.BROWSER_TYPE_UC:
- if (browserVer > 11.0) {
- _supportWebGL = true;
- } else {
- _supportWebGL = false;
- }
- break;
- case sys.BROWSER_TYPE_360:
- _supportWebGL = false;
- break;
- }
- }
+ _supportWebGL = true;
}
/**
@@ -944,7 +985,16 @@ function initSys () {
"canvas": _supportCanvas,
"opengl": _supportWebGL,
"webp": _supportWebp,
+ 'imageBitmap': false,
};
+
+ if (typeof createImageBitmap !== 'undefined' && typeof Blob !== 'undefined') {
+ _tmpCanvas1.width = _tmpCanvas1.height = 2;
+ createImageBitmap(_tmpCanvas1, {}).then(imageBitmap => {
+ capabilities.imageBitmap = true;
+ imageBitmap.close && imageBitmap.close();
+ }).catch(err => {});
+ }
if (docEle['ontouchstart'] !== undefined || doc['ontouchstart'] !== undefined || nav.msPointerEnabled)
capabilities["touches"] = true;
if (docEle['onmouseup'] !== undefined)
@@ -977,8 +1027,7 @@ function initSys () {
// check if browser supports Web Audio
// check Web Audio's context
- var supportWebAudio = sys.browserType !== sys.BROWSER_TYPE_WECHAT_GAME &&
- !!(window.AudioContext || window.webkitAudioContext || window.mozAudioContext);
+ var supportWebAudio = !!(window.AudioContext || window.webkitAudioContext || window.mozAudioContext);
__audioSupport = { ONLY_ONE: false, WEB_AUDIO: supportWebAudio, DELAY_CREATE_CTX: false };
@@ -1051,7 +1100,7 @@ function initSys () {
* !#zh
* 网络类型枚举
*
- * @enum NetworkType
+ * @enum sys.NetworkType
*/
sys.NetworkType = {
/**
@@ -1094,7 +1143,7 @@ function initSys () {
* 获取当前设备的网络类型, 如果网络类型无法获取,默认将返回 cc.sys.NetworkType.LAN
*
* @method getNetworkType
- * @return {NetworkType}
+ * @return {sys.NetworkType}
*/
sys.getNetworkType = function() {
// TODO: need to implement this for mobile phones.
@@ -1171,7 +1220,7 @@ function initSys () {
* @param {String} url
*/
sys.openURL = function (url) {
- if (CC_JSB) {
+ if (CC_JSB || CC_RUNTIME) {
jsb.openURL(url);
}
else {
diff --git a/cocos2d/core/platform/CCView.js b/cocos2d/core/platform/CCView.js
index 01547c16947..68209b4a238 100644
--- a/cocos2d/core/platform/CCView.js
+++ b/cocos2d/core/platform/CCView.js
@@ -32,9 +32,7 @@ require('../platform/CCClass');
var __BrowserGetter = {
init: function(){
- if (!CC_WECHATGAME && !CC_QQPLAY) {
- this.html = document.getElementsByTagName("html")[0];
- }
+ this.html = document.getElementsByTagName("html")[0];
},
availWidth: function(frame){
if (!frame || frame === this.html)
@@ -57,24 +55,11 @@ var __BrowserGetter = {
if (cc.sys.os === cc.sys.OS_IOS) // All browsers are WebView
__BrowserGetter.adaptationType = cc.sys.BROWSER_TYPE_SAFARI;
-if (CC_WECHATGAME) {
- if (cc.sys.browserType === cc.sys.BROWSER_TYPE_WECHAT_GAME_SUB) {
- __BrowserGetter.adaptationType = cc.sys.BROWSER_TYPE_WECHAT_GAME_SUB;
- }
- else {
- __BrowserGetter.adaptationType = cc.sys.BROWSER_TYPE_WECHAT_GAME;
- }
-}
-
-if (CC_QQPLAY) {
- __BrowserGetter.adaptationType = cc.sys.BROWSER_TYPE_QQ_PLAY;
-}
-
switch (__BrowserGetter.adaptationType) {
case cc.sys.BROWSER_TYPE_SAFARI:
- __BrowserGetter.meta["minimal-ui"] = "true";
case cc.sys.BROWSER_TYPE_SOUGOU:
case cc.sys.BROWSER_TYPE_UC:
+ __BrowserGetter.meta["minimal-ui"] = "true";
__BrowserGetter.availWidth = function(frame){
return frame.clientWidth;
};
@@ -82,23 +67,6 @@ switch (__BrowserGetter.adaptationType) {
return frame.clientHeight;
};
break;
- case cc.sys.BROWSER_TYPE_WECHAT_GAME:
- __BrowserGetter.availWidth = function(){
- return window.innerWidth;
- };
- __BrowserGetter.availHeight = function(){
- return window.innerHeight;
- };
- break;
- case cc.sys.BROWSER_TYPE_WECHAT_GAME_SUB:
- var sharedCanvas = window.sharedCanvas || wx.getSharedCanvas();
- __BrowserGetter.availWidth = function(){
- return sharedCanvas.width;
- };
- __BrowserGetter.availHeight = function(){
- return sharedCanvas.height;
- };
- break;
}
var _scissorRect = null;
@@ -116,6 +84,7 @@ var _scissorRect = null;
* - cc.view.methodName();
*
* @class View
+ * @extends EventTarget
*/
var View = function () {
EventTarget.call(this);
@@ -140,6 +109,11 @@ var View = function () {
_t._autoFullScreen = false;
// The device's pixel ratio (for retina displays)
_t._devicePixelRatio = 1;
+ if(CC_JSB) {
+ _t._maxPixelRatio = 4;
+ } else {
+ _t._maxPixelRatio = 2;
+ }
// Retina disabled by default
_t._retinaEnabled = false;
// Custom callback for resize event
@@ -165,11 +139,9 @@ var View = function () {
cc.js.extend(View, EventTarget);
-
cc.js.mixin(View.prototype, {
init () {
this._initFrameSize();
- this.enableAntiAlias(true);
var w = cc.game.canvas.width, h = cc.game.canvas.height;
this._designResolutionSize.width = w;
@@ -187,13 +159,22 @@ cc.js.mixin(View.prototype, {
},
// Resize helper functions
- _resizeEvent: function () {
+ _resizeEvent: function (forceOrEvent) {
var view;
if (this.setDesignResolutionSize) {
view = this;
} else {
view = cc.view;
}
+ // HACK: some browsers can't update window size immediately
+ // need to handle resize event callback on the next tick
+ let sys = cc.sys;
+ if (sys.browserType === sys.BROWSER_TYPE_UC && sys.os === sys.OS_IOS) {
+ setTimeout(function () {
+ view._resizeEvent(forceOrEvent);
+ }, 0)
+ return;
+ }
// Check frame size changed or not
var prevFrameW = view._frameSize.width, prevFrameH = view._frameSize.height, prevRotated = view._isRotated;
@@ -209,7 +190,7 @@ cc.js.mixin(View.prototype, {
else {
view._initFrameSize();
}
- if (view._isRotated === prevRotated && view._frameSize.width === prevFrameW && view._frameSize.height === prevFrameH)
+ if (forceOrEvent !== true && view._isRotated === prevRotated && view._frameSize.width === prevFrameW && view._frameSize.height === prevFrameH)
return;
// Frame size changed, do resize works
@@ -229,6 +210,21 @@ cc.js.mixin(View.prototype, {
_orientationChange: function () {
cc.view._orientationChanging = true;
cc.view._resizeEvent();
+ // HACK: show nav bar on iOS safari
+ // safari will enter fullscreen when rotate to landscape
+ // need to exit fullscreen when rotate back to portrait, scrollTo(0, 1) works.
+ if (cc.sys.browserType === cc.sys.BROWSER_TYPE_SAFARI && cc.sys.isMobile) {
+ setTimeout(() => {
+ if (window.innerHeight > window.innerWidth) {
+ window.scrollTo(0, 1);
+ }
+ }, 500);
+ }
+ },
+
+ _resize: function() {
+ //force resize when size is changed at native
+ cc.view._resizeEvent(CC_JSB);
},
/**
@@ -269,14 +265,14 @@ cc.js.mixin(View.prototype, {
//enable
if (!this._resizeWithBrowserSize) {
this._resizeWithBrowserSize = true;
- window.addEventListener('resize', this._resizeEvent);
+ window.addEventListener('resize', this._resize);
window.addEventListener('orientationchange', this._orientationChange);
}
} else {
//disable
if (this._resizeWithBrowserSize) {
this._resizeWithBrowserSize = false;
- window.removeEventListener('resize', this._resizeEvent);
+ window.removeEventListener('resize', this._resize);
window.removeEventListener('orientationchange', this._orientationChange);
}
}
@@ -296,6 +292,7 @@ cc.js.mixin(View.prototype, {
* @param {Function|Null} callback - The callback function
*/
setResizeCallback: function (callback) {
+ if (CC_EDITOR) return;
if (typeof callback === 'function' || callback == null) {
this._resizeCallback = callback;
}
@@ -348,15 +345,6 @@ cc.js.mixin(View.prototype, {
cc.game.container.style['-webkit-transform-origin'] = '0px 0px 0px';
cc.game.container.style.transformOrigin = '0px 0px 0px';
this._isRotated = true;
-
- // Fix for issue: https://github.com/cocos-creator/fireball/issues/8365
- // Reference: https://www.douban.com/note/343402554/
- // For Chrome, z-index not working after container transform rotate 90deg.
- // Because 'transform' style adds canvas (the top-element of container) to a new stack context.
- // That causes the DOM Input was hidden under canvas.
- // This should be done after container rotated, instead of in style-mobile.css.
- cc.game.canvas.style['-webkit-transform'] = 'translateZ(0px)';
- cc.game.canvas.style.transform = 'translateZ(0px)';
}
if (this._orientationChanging) {
setTimeout(function () {
@@ -365,14 +353,6 @@ cc.js.mixin(View.prototype, {
}
},
- // hack
- _adjustSizeKeepCanvasSize: function () {
- var designWidth = this._originalDesignResolutionSize.width;
- var designHeight = this._originalDesignResolutionSize.height;
- if (designWidth > 0)
- this.setDesignResolutionSize(designWidth, designHeight, this._resolutionPolicy);
- },
-
_setViewportMeta: function (metas, overwrite) {
var vp = document.getElementById("cocosMetaElement");
if(vp && overwrite){
@@ -395,7 +375,7 @@ cc.js.mixin(View.prototype, {
}
else if (overwrite) {
pattern = new RegExp(key+"\s*=\s*[^,]+");
- content.replace(pattern, key + "=" + metas[key]);
+ content = content.replace(pattern, key + "=" + metas[key]);
}
}
if(/^,/.test(content))
@@ -410,7 +390,7 @@ cc.js.mixin(View.prototype, {
},
_adjustViewportMeta: function () {
- if (this._isAdjustViewport && !CC_JSB && !CC_WECHATGAME && !CC_QQPLAY) {
+ if (this._isAdjustViewport && !CC_JSB && !CC_RUNTIME) {
this._setViewportMeta(__BrowserGetter.meta, false);
this._isAdjustViewport = false;
}
@@ -445,6 +425,10 @@ cc.js.mixin(View.prototype, {
* @param {Boolean} enabled - Enable or disable retina display
*/
enableRetina: function(enabled) {
+ if (CC_EDITOR && enabled) {
+ cc.warn('Can not enable retina in Editor.');
+ return;
+ }
this._retinaEnabled = !!enabled;
},
@@ -458,6 +442,9 @@ cc.js.mixin(View.prototype, {
* @return {Boolean}
*/
isRetinaEnabled: function() {
+ if (CC_EDITOR) {
+ return false;
+ }
return this._retinaEnabled;
},
@@ -466,27 +453,28 @@ cc.js.mixin(View.prototype, {
* !#zh 控制抗锯齿是否开启
* @method enableAntiAlias
* @param {Boolean} enabled - Enable or not anti-alias
+ * @deprecated cc.view.enableAntiAlias is deprecated, please use cc.Texture2D.setFilters instead
+ * @since v2.3.0
*/
enableAntiAlias: function (enabled) {
+ cc.warnID(9200);
if (this._antiAliasEnabled === enabled) {
return;
}
this._antiAliasEnabled = enabled;
if(cc.game.renderType === cc.game.RENDER_TYPE_WEBGL) {
- var cache = cc.loader._cache;
- for (var key in cache) {
- var item = cache[key];
- var tex = item && item.content instanceof cc.Texture2D ? item.content : null;
- if (tex) {
+ var cache = cc.assetManager.assets;
+ cache.forEach(function (asset) {
+ if (asset instanceof cc.Texture2D) {
var Filter = cc.Texture2D.Filter;
if (enabled) {
- tex.setFilters(Filter.LINEAR, Filter.LINEAR);
+ asset.setFilters(Filter.LINEAR, Filter.LINEAR);
}
else {
- tex.setFilters(Filter.NEAREST, Filter.NEAREST);
+ asset.setFilters(Filter.NEAREST, Filter.NEAREST);
}
}
- }
+ });
}
else if(cc.game.renderType === cc.game.RENDER_TYPE_CANVAS) {
var ctx = cc.game.canvas.getContext('2d');
@@ -517,14 +505,14 @@ cc.js.mixin(View.prototype, {
enableAutoFullScreen: function(enabled) {
if (enabled &&
enabled !== this._autoFullScreen &&
- cc.sys.isMobile &&
- cc.sys.browserType !== cc.sys.BROWSER_TYPE_WECHAT) {
+ cc.sys.isMobile) {
// Automatically full screen when user touches on mobile version
this._autoFullScreen = true;
cc.screen.autoFullScreen(cc.game.frame);
}
else {
this._autoFullScreen = false;
+ cc.screen.disableAutoFullScreen(cc.game.frame);
}
},
@@ -610,7 +598,7 @@ cc.js.mixin(View.prototype, {
this._frameSize.height = height;
cc.game.frame.style.width = width + "px";
cc.game.frame.style.height = height + "px";
- this._resizeEvent();
+ this._resizeEvent(true);
},
/**
@@ -718,8 +706,8 @@ cc.js.mixin(View.prototype, {
*/
setDesignResolutionSize: function (width, height, resolutionPolicy) {
// Defensive code
- if( !(width > 0 || height > 0) ){
- cc.logID(2200);
+ if( !(width > 0 && height > 0) ){
+ cc.errorID(2200);
return;
}
@@ -777,6 +765,7 @@ cc.js.mixin(View.prototype, {
cc.visibleRect && cc.visibleRect.init(this._visibleRect);
renderer.updateCameraViewport();
+ cc.internal.inputManager._updateCanvasBoundingRect();
this.emit('design-resolution-changed');
},
@@ -811,7 +800,7 @@ cc.js.mixin(View.prototype, {
* @param {ResolutionPolicy|Number} resolutionPolicy The resolution policy desired
*/
setRealPixelResolution: function (width, height, resolutionPolicy) {
- if (!CC_JSB && !CC_WECHATGAME && !CC_QQPLAY) {
+ if (!CC_JSB && !CC_RUNTIME) {
// Set viewport's width
this._setViewportMeta({"width": width}, true);
@@ -969,8 +958,10 @@ cc.js.mixin(View.prototype, {
*/
convertToLocationInView: function (tx, ty, relatedPos, out) {
let result = out || cc.v2();
- let x = this._devicePixelRatio * (tx - relatedPos.left);
- let y = this._devicePixelRatio * (relatedPos.top + relatedPos.height - ty);
+ let posLeft = relatedPos.adjustedLeft ? relatedPos.adjustedLeft : relatedPos.left;
+ let posTop = relatedPos.adjustedTop ? relatedPos.adjustedTop : relatedPos.top;
+ let x = this._devicePixelRatio * (tx - posLeft);
+ let y = this._devicePixelRatio * (posTop + relatedPos.height - ty);
if (this._isRotated) {
result.x = cc.game.canvas.width - y;
result.y = x;
@@ -1011,16 +1002,16 @@ cc.js.mixin(View.prototype, {
});
/**
- * !en
+ * !#en
* Emit when design resolution changed.
- * !zh
+ * !#zh
* 当设计分辨率改变时发送。
* @event design-resolution-changed
*/
/**
- * !en
+ * !#en
* Emit when canvas resize.
- * !zh
+ * !#zh
* 当画布大小改变时发送。
* @event canvas-resize
*/
@@ -1067,26 +1058,35 @@ cc.ContainerStrategy = cc.Class({
},
_setupContainer: function (view, w, h) {
- var locCanvas = cc.game.canvas, locContainer = cc.game.container;
+ var locCanvas = cc.game.canvas;
- if (cc.sys.platform !== cc.sys.WECHAT_GAME) {
- if (cc.sys.os === cc.sys.OS_ANDROID) {
- document.body.style.width = (view._isRotated ? h : w) + 'px';
- document.body.style.height = (view._isRotated ? w : h) + 'px';
- }
- // Setup style
- locContainer.style.width = locCanvas.style.width = w + 'px';
- locContainer.style.height = locCanvas.style.height = h + 'px';
- }
+ this._setupStyle(view, w, h);
+
// Setup pixel ratio for retina display
var devicePixelRatio = view._devicePixelRatio = 1;
- if (view.isRetinaEnabled())
- devicePixelRatio = view._devicePixelRatio = Math.min(2, window.devicePixelRatio || 1);
+ if(CC_JSB){
+ // view.isRetinaEnabled only work on web.
+ devicePixelRatio = view._devicePixelRatio = window.devicePixelRatio;
+ }else if (view.isRetinaEnabled()) {
+ devicePixelRatio = view._devicePixelRatio = Math.min(view._maxPixelRatio, window.devicePixelRatio || 1);
+ }
// Setup canvas
locCanvas.width = w * devicePixelRatio;
locCanvas.height = h * devicePixelRatio;
},
+ _setupStyle: function (view, w, h) {
+ let locCanvas = cc.game.canvas;
+ let locContainer = cc.game.container;
+ if (cc.sys.os === cc.sys.OS_ANDROID) {
+ document.body.style.width = (view._isRotated ? h : w) + 'px';
+ document.body.style.height = (view._isRotated ? w : h) + 'px';
+ }
+ // Setup style
+ locContainer.style.width = locCanvas.style.width = w + 'px';
+ locContainer.style.height = locCanvas.style.height = h + 'px';
+ },
+
_fixContainer: function () {
// Add container to document body
document.body.insertBefore(cc.game.container, document.body.firstChild);
@@ -1125,9 +1125,7 @@ cc.ContentStrategy = cc.Class({
Math.abs(containerW - contentW) < 2 && (contentW = containerW);
Math.abs(containerH - contentH) < 2 && (contentH = containerH);
- var viewport = cc.rect(Math.round((containerW - contentW) / 2),
- Math.round((containerH - contentH) / 2),
- contentW, contentH);
+ var viewport = cc.rect((containerW - contentW) / 2, (containerH - contentH) / 2, contentW, contentH);
// Translate the content
if (cc.game.renderType === cc.game.RENDER_TYPE_CANVAS){
@@ -1285,6 +1283,18 @@ cc.ContentStrategy = cc.Class({
}
});
+ // need to adapt prototype before instantiating
+ let _global = typeof window === 'undefined' ? global : window;
+ let globalAdapter = _global.__globalAdapter;
+ if (globalAdapter) {
+ if (globalAdapter.adaptContainerStrategy) {
+ globalAdapter.adaptContainerStrategy(cc.ContainerStrategy.prototype);
+ }
+ if (globalAdapter.adaptView) {
+ globalAdapter.adaptView(View.prototype);
+ }
+ }
+
// #NOT STABLE on Android# Alias: Strategy that makes the container's size equals to the window's size
// cc.ContainerStrategy.EQUAL_TO_WINDOW = new EqualToWindow();
// #NOT STABLE on Android# Alias: Strategy that scale proportionally the container's size to window's size
@@ -1544,6 +1554,6 @@ cc.view = new View();
* @property winSize
* @type Size
*/
-cc.winSize = cc.v2();
+cc.winSize = cc.size();
module.exports = cc.view;
diff --git a/cocos2d/core/platform/CCVisibleRect.js b/cocos2d/core/platform/CCVisibleRect.js
index 9fc0e57b544..2512fd9d6ce 100644
--- a/cocos2d/core/platform/CCVisibleRect.js
+++ b/cocos2d/core/platform/CCVisibleRect.js
@@ -46,6 +46,7 @@ cc.visibleRect = {
/**
* initialize
+ * @static
* @method init
* @param {Rect} visibleRect
*/
@@ -90,56 +91,67 @@ cc.visibleRect = {
/**
* Top left coordinate of the screen related to the game scene.
+ * @static
* @property {Vec2} topLeft
*/
/**
* Top right coordinate of the screen related to the game scene.
+ * @static
* @property {Vec2} topRight
*/
/**
* Top center coordinate of the screen related to the game scene.
+ * @static
* @property {Vec2} top
*/
/**
* Bottom left coordinate of the screen related to the game scene.
+ * @static
* @property {Vec2} bottomLeft
*/
/**
* Bottom right coordinate of the screen related to the game scene.
+ * @static
* @property {Vec2} bottomRight
*/
/**
* Bottom center coordinate of the screen related to the game scene.
+ * @static
* @property {Vec2} bottom
*/
/**
* Center coordinate of the screen related to the game scene.
+ * @static
* @property {Vec2} center
*/
/**
* Left center coordinate of the screen related to the game scene.
+ * @static
* @property {Vec2} left
*/
/**
* Right center coordinate of the screen related to the game scene.
+ * @static
* @property {Vec2} right
*/
/**
* Width of the screen.
+ * @static
* @property {Number} width
*/
/**
* Height of the screen.
+ * @static
* @property {Number} height
*/
diff --git a/cocos2d/core/platform/attribute.js b/cocos2d/core/platform/attribute.js
index f60548fad00..59bed02d1f3 100644
--- a/cocos2d/core/platform/attribute.js
+++ b/cocos2d/core/platform/attribute.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -29,31 +29,19 @@ var isPlainEmptyObj = require('./utils').isPlainEmptyObj_DEV;
const DELIMETER = '$_$';
-function createAttrsSingle (owner, ownerCtor, superAttrs) {
- var AttrsCtor;
- if (CC_DEV && CC_SUPPORT_JIT) {
- var ctorName = ownerCtor.name;
- if (owner === ownerCtor) {
- ctorName += '_ATTRS';
- }
- else {
- ctorName += '_ATTRS_INSTANCE';
- }
- AttrsCtor = Function('return (function ' + ctorName + '(){});')();
- }
- else {
- AttrsCtor = function () {};
- }
- if (superAttrs) {
- js.extend(AttrsCtor, superAttrs.constructor);
- }
- var attrs = new AttrsCtor();
+function createAttrsSingle (owner, superAttrs) {
+ var attrs = superAttrs ? Object.create(superAttrs) : {};
js.value(owner, '__attrs__', attrs);
return attrs;
}
// subclass should not have __attrs__
function createAttrs (subclass) {
+ if (typeof subclass !== 'function') {
+ // attributes only in instance
+ let instance = subclass;
+ return createAttrsSingle(instance, getClassAttrs(instance.constructor));
+ }
var superClass;
var chains = cc.Class.getInheritanceChain(subclass);
for (var i = chains.length - 1; i >= 0; i--) {
@@ -61,11 +49,11 @@ function createAttrs (subclass) {
var attrs = cls.hasOwnProperty('__attrs__') && cls.__attrs__;
if (!attrs) {
superClass = chains[i + 1];
- createAttrsSingle(cls, cls, superClass && superClass.__attrs__);
+ createAttrsSingle(cls, superClass && superClass.__attrs__);
}
}
superClass = chains[0];
- createAttrsSingle(subclass, subclass, superClass && superClass.__attrs__);
+ createAttrsSingle(subclass, superClass && superClass.__attrs__);
return subclass.__attrs__;
}
@@ -84,46 +72,23 @@ function createAttrs (subclass) {
// * @static
// * @private
function attr (ctor, propName, newAttrs) {
- var attrs, setter, key;
- if (typeof ctor === 'function') {
- // attributes shared between instances
- attrs = getClassAttrs(ctor);
- setter = attrs.constructor.prototype;
- }
- else {
- // attributes in instance
- var instance = ctor;
- attrs = instance.__attrs__;
- if (!attrs) {
- ctor = instance.constructor;
- var clsAttrs = getClassAttrs(ctor);
- attrs = createAttrsSingle(instance, ctor, clsAttrs);
- }
- setter = attrs;
- }
-
- if (typeof newAttrs === 'undefined') {
+ var attrs = getClassAttrs(ctor);
+ if (!CC_DEV || typeof newAttrs === 'undefined') {
// get
var prefix = propName + DELIMETER;
var ret = {};
- for (key in attrs) {
+ for (let key in attrs) {
if (key.startsWith(prefix)) {
ret[key.slice(prefix.length)] = attrs[key];
}
}
return ret;
}
- else {
+ else if (CC_DEV && typeof newAttrs === 'object') {
// set
- if (typeof newAttrs === 'object') {
- for (key in newAttrs) {
- if (key.charCodeAt(0) !== 95 /* _ */) {
- setter[propName + DELIMETER + key] = newAttrs[key];
- }
- }
- }
- else if (CC_DEV) {
- cc.errorID(3629);
+ cc.warn(`\`cc.Class.attr(obj, prop, { key: value });\` is deprecated, use \`cc.Class.Attr.setClassAttr(obj, prop, 'key', value);\` instead please.`);
+ for (let key in newAttrs) {
+ attrs[propName + DELIMETER + key] = newAttrs[key];
}
}
}
@@ -133,20 +98,22 @@ function getClassAttrs (ctor) {
return (ctor.hasOwnProperty('__attrs__') && ctor.__attrs__) || createAttrs(ctor);
}
-// returns a writable meta object, used to set multi attributes
-function getClassAttrsProto (ctor) {
- return getClassAttrs(ctor).constructor.prototype;
-}
-
function setClassAttr (ctor, propName, key, value) {
- var proto = getClassAttrsProto(ctor);
- proto[propName + DELIMETER + key] = value;
+ getClassAttrs(ctor)[propName + DELIMETER + key] = value;
}
/**
* @module cc
*/
+function PrimitiveType (name, def) {
+ this.name = name;
+ this.default = def;
+}
+PrimitiveType.prototype.toString = function () {
+ return this.name;
+};
+
/**
* Specify that the input value must be integer in Inspector.
* Also used to indicates that the elements in array should be type integer.
@@ -164,7 +131,7 @@ function setClassAttr (ctor, propName, key, value) {
* })
* member = [];
*/
-cc.Integer = 'Integer';
+cc.Integer = new PrimitiveType('Integer', 0);
/**
* Indicates that the elements in array should be type double.
@@ -182,7 +149,7 @@ cc.Integer = 'Integer';
* })
* member = [];
*/
-cc.Float = 'Float';
+cc.Float = new PrimitiveType('Float', 0);
if (CC_EDITOR) {
js.get(cc, 'Number', function () {
@@ -207,7 +174,7 @@ if (CC_EDITOR) {
* })
* member = [];
*/
-cc.Boolean = 'Boolean';
+cc.Boolean = new PrimitiveType('Boolean', false);
/**
* Indicates that the elements in array should be type string.
@@ -225,128 +192,95 @@ cc.Boolean = 'Boolean';
* })
* member = [];
*/
-cc.String = 'String';
-
-/*
-BuiltinAttributes: {
- default: defaultValue,
- _canUsedInSetter: false, (default false) (NYI)
-}
-Getter or Setter: {
- hasGetter: true,
- hasSetter: true,
-}
-Callbacks: {
- _onAfterProp: function (constructor, propName) {},
- _onAfterGetter: function (constructor, propName) {}, (NYI)
- _onAfterSetter: function (constructor, propName) {}, (NYI)
-}
- */
+cc.String = new PrimitiveType('String', '');
+// Ensures the type matches its default value
function getTypeChecker (type, attrName) {
- if (CC_DEV) {
- return function (constructor, mainPropName) {
- var propInfo = '"' + js.getClassName(constructor) + '.' + mainPropName + '"';
- var mainPropAttrs = attr(constructor, mainPropName);
- if (!mainPropAttrs.saveUrlAsAsset) {
- var mainPropAttrsType = mainPropAttrs.type;
- if (mainPropAttrsType === cc.Integer || mainPropAttrsType === cc.Float) {
- mainPropAttrsType = 'Number';
+ return function (constructor, mainPropName) {
+ var propInfo = '"' + js.getClassName(constructor) + '.' + mainPropName + '"';
+ var mainPropAttrs = attr(constructor, mainPropName);
+
+ var mainPropAttrsType = mainPropAttrs.type;
+ if (mainPropAttrsType === cc.Integer || mainPropAttrsType === cc.Float) {
+ mainPropAttrsType = 'Number';
+ }
+ else if (mainPropAttrsType === cc.String || mainPropAttrsType === cc.Boolean) {
+ mainPropAttrsType = '' + mainPropAttrsType;
+ }
+ if (mainPropAttrsType !== type) {
+ cc.warnID(3604, propInfo);
+ return;
+ }
+
+ if (!mainPropAttrs.hasOwnProperty('default')) {
+ return;
+ }
+ var defaultVal = mainPropAttrs.default;
+ if (typeof defaultVal === 'undefined') {
+ return;
+ }
+ var isContainer = Array.isArray(defaultVal) || isPlainEmptyObj(defaultVal);
+ if (isContainer) {
+ return;
+ }
+ var defaultType = typeof defaultVal;
+ var type_lowerCase = type.toLowerCase();
+ if (defaultType === type_lowerCase) {
+ if (type_lowerCase === 'object') {
+ if (defaultVal && !(defaultVal instanceof mainPropAttrs.ctor)) {
+ cc.warnID(3605, propInfo, js.getClassName(mainPropAttrs.ctor));
}
- if (mainPropAttrsType !== type) {
- cc.warnID(3604, propInfo);
+ else {
return;
}
}
- if (!mainPropAttrs.hasOwnProperty('default')) {
- return;
- }
- var defaultVal = mainPropAttrs.default;
- if (typeof defaultVal === 'undefined') {
- return;
+ else if (type !== 'Number') {
+ cc.warnID(3606, attrName, propInfo, type);
}
- var isContainer = Array.isArray(defaultVal) || isPlainEmptyObj(defaultVal);
- if (isContainer) {
- return;
- }
- var defaultType = typeof defaultVal;
- var type_lowerCase = type.toLowerCase();
- if (defaultType === type_lowerCase) {
- if (!mainPropAttrs.saveUrlAsAsset) {
- if (type_lowerCase === 'object') {
- if (defaultVal && !(defaultVal instanceof mainPropAttrs.ctor)) {
- cc.warnID(3605, propInfo, js.getClassName(mainPropAttrs.ctor));
- }
- else {
- return;
- }
- }
- else if (type !== 'Number') {
- cc.warnID(3606, attrName, propInfo, type);
- }
- }
- }
- else if (defaultType !== 'function') {
- if (type === cc.String && defaultVal == null) {
- if (!js.isChildClassOf(mainPropAttrs.ctor, cc.RawAsset)) {
- cc.warnID(3607, propInfo);
- }
- }
- else if (mainPropAttrs.ctor === String && (defaultType === 'string' || defaultVal == null)) {
- mainPropAttrs.type = cc.String;
- cc.warnID(3608, propInfo);
- }
- else if (mainPropAttrs.ctor === Boolean && defaultType === 'boolean') {
- mainPropAttrs.type = cc.Boolean;
- cc.warnID(3609, propInfo);
- }
- else if (mainPropAttrs.ctor === Number && defaultType === 'number') {
- mainPropAttrs.type = cc.Float;
- cc.warnID(3610, propInfo);
- }
- else {
- cc.warnID(3611, attrName, propInfo, defaultType);
- }
+ }
+ else if (defaultType !== 'function') {
+ if (type === cc.String && defaultVal == null) {
+ cc.warnID(3607, propInfo);
}
else {
- return;
+ cc.warnID(3611, attrName, propInfo, defaultType);
}
- delete mainPropAttrs.type;
- };
- }
+ }
+ else {
+ return;
+ }
+ delete mainPropAttrs.type;
+ };
}
-function ObjectType (typeCtor) {
- return {
- type: 'Object',
- ctor: typeCtor,
- _onAfterProp: CC_DEV && function (classCtor, mainPropName) {
- getTypeChecker('Object', 'type')(classCtor, mainPropName);
- // check ValueType
- var defaultDef = getClassAttrs(classCtor)[mainPropName + DELIMETER + 'default'];
- var defaultVal = require('./CCClass').getDefault(defaultDef);
- if (!Array.isArray(defaultVal) && js.isChildClassOf(typeCtor, cc.ValueType)) {
- var typename = js.getClassName(typeCtor);
- var info = cc.js.formatStr('No need to specify the "type" of "%s.%s" because %s is a child class of ValueType.',
- js.getClassName(classCtor), mainPropName, typename);
- if (defaultDef) {
- cc.log(info);
- }
- else {
- cc.warnID(3612, info, typename, js.getClassName(classCtor), mainPropName, typename);
- }
+// Ensures the type matches its default value
+function getObjTypeChecker (typeCtor) {
+ return function (classCtor, mainPropName) {
+ getTypeChecker('Object', 'type')(classCtor, mainPropName);
+ // check ValueType
+ var defaultDef = getClassAttrs(classCtor)[mainPropName + DELIMETER + 'default'];
+ var defaultVal = require('./CCClass').getDefault(defaultDef);
+ if (!Array.isArray(defaultVal) && js.isChildClassOf(typeCtor, cc.ValueType)) {
+ var typename = js.getClassName(typeCtor);
+ var info = cc.js.formatStr('No need to specify the "type" of "%s.%s" because %s is a child class of ValueType.',
+ js.getClassName(classCtor), mainPropName, typename);
+ if (defaultDef) {
+ cc.log(info);
+ }
+ else {
+ cc.warnID(3612, info, typename, js.getClassName(classCtor), mainPropName, typename);
}
}
};
}
module.exports = {
+ PrimitiveType,
attr: attr,
getClassAttrs: getClassAttrs,
- getClassAttrsProto: getClassAttrsProto,
setClassAttr: setClassAttr,
DELIMETER: DELIMETER,
- getTypeChecker: getTypeChecker,
- ObjectType: ObjectType,
+ getTypeChecker_ET: ((CC_EDITOR && !Editor.isBuilder) || CC_TEST) && getTypeChecker,
+ getObjTypeChecker_ET: ((CC_EDITOR && !Editor.isBuilder) || CC_TEST) && getObjTypeChecker,
ScriptUuid: {}, // the value will be represented as a uuid string
};
diff --git a/cocos2d/core/platform/callbacks-invoker.js b/cocos2d/core/platform/callbacks-invoker.js
index 72d38d73b3b..803c8fcc6fb 100644
--- a/cocos2d/core/platform/callbacks-invoker.js
+++ b/cocos2d/core/platform/callbacks-invoker.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -27,88 +27,170 @@
const js = require('./js');
const fastRemoveAt = js.array.fastRemoveAt;
+function empty () {}
+
+function CallbackInfo () {
+ this.callback = empty;
+ this.target = undefined;
+ this.once = false;
+}
+
+CallbackInfo.prototype.set = function (callback, target, once) {
+ this.callback = callback;
+ this.target = target;
+ this.once = !!once;
+};
+
+let callbackInfoPool = new js.Pool(function (info) {
+ info.callback = empty;
+ info.target = undefined;
+ info.once = false;
+ return true;
+}, 32);
+
+callbackInfoPool.get = function () {
+ return this._get() || new CallbackInfo();
+};
+
function CallbackList () {
- this.callbacks = [];
- this.targets = []; // same length with callbacks, nullable
+ this.callbackInfos = [];
this.isInvoking = false;
this.containCanceled = false;
}
-var proto = CallbackList.prototype;
-
-proto.removeBy = function (array, value) {
- var callbacks = this.callbacks;
- var targets = this.targets;
- for (var i = 0; i < array.length; ++i) {
- if (array[i] === value) {
- fastRemoveAt(callbacks, i);
- fastRemoveAt(targets, i);
+
+let proto = CallbackList.prototype;
+
+/**
+ * !#zh
+ * 从列表中移除与指定目标相同回调函数的事件。
+ * @param cb
+ */
+proto.removeByCallback = function (cb) {
+ for (let i = 0; i < this.callbackInfos.length; ++i) {
+ let info = this.callbackInfos[i];
+ if (info && info.callback === cb) {
+ callbackInfoPool.put(info);
+ fastRemoveAt(this.callbackInfos, i);
+ --i;
+ }
+ }
+};
+
+/**
+ * !#zh
+ * 从列表中移除与指定目标相同调用者的事件。
+ * @param target
+ */
+proto.removeByTarget = function (target) {
+ for (let i = 0; i < this.callbackInfos.length; ++i) {
+ const info = this.callbackInfos[i];
+ if (info && info.target === target) {
+ callbackInfoPool.put(info);
+ fastRemoveAt(this.callbackInfos, i);
--i;
}
}
};
+/**
+ * !#zh
+ * 移除指定编号事件。
+ *
+ * @param index
+ */
proto.cancel = function (index) {
- this.callbacks[index] = this.targets[index] = null;
+ const info = this.callbackInfos[index];
+ if (info) {
+ callbackInfoPool.put(info);
+ this.callbackInfos[index] = null;
+ }
this.containCanceled = true;
};
+/**
+ * !#zh
+ * 注销所有事件。
+ */
proto.cancelAll = function () {
- let callbacks = this.callbacks;
- let targets = this.targets;
- for (let i = 0; i < callbacks.length; i++) {
- callbacks[i] = targets[i] = null;
+ for (let i = 0; i < this.callbackInfos.length; i++) {
+ const info = this.callbackInfos[i];
+ if (info) {
+ callbackInfoPool.put(info);
+ this.callbackInfos[i] = null;
+ }
}
this.containCanceled = true;
};
// filter all removed callbacks and compact array
proto.purgeCanceled = function () {
- this.removeBy(this.callbacks, null);
+ for (let i = this.callbackInfos.length - 1; i >= 0; --i) {
+ const info = this.callbackInfos[i];
+ if (!info) {
+ fastRemoveAt(this.callbackInfos, i);
+ }
+ }
this.containCanceled = false;
};
+proto.clear = function () {
+ this.cancelAll();
+ this.callbackInfos.length = 0;
+ this.isInvoking = false;
+ this.containCanceled = false;
+};
const MAX_SIZE = 16;
-const callbackListPool = new js.Pool(function (list) {
- list.callbacks.length = 0;
- list.targets.length = 0;
- list.isInvoking = false;
- list.containCanceled = false;
+let callbackListPool = new js.Pool(function (info) {
+ info.callbackInfos = [];
+ info.isInvoking = false;
+ info.containCanceled = false;
+ return true;
}, MAX_SIZE);
+
callbackListPool.get = function () {
return this._get() || new CallbackList();
};
/**
- * The CallbacksHandler is an abstract class that can register and unregister callbacks by key.
- * Subclasses should implement their own methods about how to invoke the callbacks.
- * @class _CallbacksHandler
- *
- * @private
+ * !#en The callbacks invoker to handle and invoke callbacks by key.
+ * !#zh CallbacksInvoker 用来根据 Key 管理并调用回调方法。
+ * @class CallbacksInvoker
*/
-function CallbacksHandler () {
+function CallbacksInvoker () {
this._callbackTable = js.createMap(true);
}
-proto = CallbacksHandler.prototype;
+
+proto = CallbacksInvoker.prototype;
/**
- * @method add
- * @param {String} key
- * @param {Function} callback
- * @param {Object} [target] - can be null
+ * !#zh
+ * 事件添加管理
+ *
+ * @param key
+ * @param callback
+ * @param target
+ * @param once
*/
-proto.add = function (key, callback, target) {
- var list = this._callbackTable[key];
+proto.on = function (key, callback, target, once) {
+ let list = this._callbackTable[key];
if (!list) {
list = this._callbackTable[key] = callbackListPool.get();
}
- list.callbacks.push(callback);
- list.targets.push(target || null);
+ let info = callbackInfoPool.get();
+ info.set(callback, target, once);
+ list.callbackInfos.push(info);
};
/**
+ *
+ * !#zh
+ * 检查指定事件是否已注册回调。
+ *
+ * !#en
* Check if the specified key has any registered callback. If a callback is also specified,
* it will only return true if the callback is registered.
+ *
* @method hasEventListener
* @param {String} key
* @param {Function} [callback]
@@ -116,32 +198,31 @@ proto.add = function (key, callback, target) {
* @return {Boolean}
*/
proto.hasEventListener = function (key, callback, target) {
- var list = this._callbackTable[key];
+ const list = this._callbackTable[key];
if (!list) {
return false;
}
// check any valid callback
- var callbacks = list.callbacks;
+ const infos = list.callbackInfos;
if (!callback) {
// Make sure no cancelled callbacks
if (list.isInvoking) {
- for (let i = 0; i < callbacks.length; i++) {
- if (callbacks[i]) {
+ for (let i = 0; i < infos.length; ++i) {
+ if (infos[i]) {
return true;
}
}
return false;
}
else {
- return callbacks.length > 0;
+ return infos.length > 0;
}
}
- target = target || null;
- var targets = list.targets;
- for (let i = 0; i < callbacks.length; ++i) {
- if (callbacks[i] === callback && targets[i] === target) {
+ for (let i = 0; i < infos.length; ++i) {
+ const info = infos[i];
+ if (info && info.callback === callback && info.target === target) {
return true;
}
}
@@ -149,6 +230,10 @@ proto.hasEventListener = function (key, callback, target) {
};
/**
+ * !#zh
+ * 移除在特定事件类型中注册的所有回调或在某个目标中注册的所有回调。
+ *
+ * !#en
* Removes all callbacks registered in a certain event type or all callbacks registered with a certain target
* @method removeAll
* @param {String|Object} keyOrTarget - The event key to be removed or the target to be removed
@@ -156,12 +241,13 @@ proto.hasEventListener = function (key, callback, target) {
proto.removeAll = function (keyOrTarget) {
if (typeof keyOrTarget === 'string') {
// remove by key
- let list = this._callbackTable[keyOrTarget];
+ const list = this._callbackTable[keyOrTarget];
if (list) {
if (list.isInvoking) {
list.cancelAll();
}
else {
+ list.clear();
callbackListPool.put(list);
delete this._callbackTable[keyOrTarget];
}
@@ -169,43 +255,46 @@ proto.removeAll = function (keyOrTarget) {
}
else if (keyOrTarget) {
// remove by target
- for (let key in this._callbackTable) {
- let list = this._callbackTable[key];
+ for (const key in this._callbackTable) {
+ const list = this._callbackTable[key];
if (list.isInvoking) {
- let targets = list.targets;
- for (let i = 0; i < targets.length; ++i) {
- if (targets[i] === keyOrTarget) {
+ const infos = list.callbackInfos;
+ for (let i = 0; i < infos.length; ++i) {
+ const info = infos[i];
+ if (info && info.target === keyOrTarget) {
list.cancel(i);
}
}
}
else {
- list.removeBy(list.targets, keyOrTarget);
+ list.removeByTarget(keyOrTarget);
}
}
}
};
/**
- * @method remove
+ * !#zh
+ * 删除之前与同类型,回调,目标注册的回调。
+ *
+ * @method off
* @param {String} key
* @param {Function} callback
* @param {Object} [target]
*/
-proto.remove = function (key, callback, target) {
- var list = this._callbackTable[key];
+proto.off = function (key, callback, target) {
+ const list = this._callbackTable[key];
if (list) {
- target = target || null;
- var callbacks = list.callbacks;
- var targets = list.targets;
- for (var i = 0; i < callbacks.length; ++i) {
- if (callbacks[i] === callback && targets[i] === target) {
+ const infos = list.callbackInfos;
+ for (let i = 0; i < infos.length; ++i) {
+ const info = infos[i];
+ if (info && info.callback === callback && info.target === target) {
if (list.isInvoking) {
list.cancel(i);
}
else {
- fastRemoveAt(callbacks, i);
- fastRemoveAt(targets, i);
+ fastRemoveAt(infos, i);
+ callbackInfoPool.put(info);
}
break;
}
@@ -215,47 +304,44 @@ proto.remove = function (key, callback, target) {
/**
- * !#en The callbacks invoker to handle and invoke callbacks by key.
- * !#zh CallbacksInvoker 用来根据 Key 管理并调用回调方法。
- * @class CallbacksInvoker
+ * !#en
+ * Trigger an event directly with the event name and necessary arguments.
+ * !#zh
+ * 通过事件名发送自定义事件
*
- * @extends _CallbacksHandler
- */
-var CallbacksInvoker = function () {
- CallbacksHandler.call(this);
-};
-js.extend(CallbacksInvoker, CallbacksHandler);
-
-if (CC_TEST) {
- cc._Test.CallbacksInvoker = CallbacksInvoker;
-}
-
-/**
- * @method invoke
- * @param {String} key
- * @param {any} [p1]
- * @param {any} [p2]
- * @param {any} [p3]
- * @param {any} [p4]
- * @param {any} [p5]
+ * @method emit
+ * @param {String} key - event type
+ * @param {*} [arg1] - First argument
+ * @param {*} [arg2] - Second argument
+ * @param {*} [arg3] - Third argument
+ * @param {*} [arg4] - Fourth argument
+ * @param {*} [arg5] - Fifth argument
+ * @example
+ *
+ * eventTarget.emit('fire', event);
+ * eventTarget.emit('fire', message, emitter);
*/
-CallbacksInvoker.prototype.invoke = function (key, p1, p2, p3, p4, p5) {
- var list = this._callbackTable[key];
+proto.emit = function (key, arg1, arg2, arg3, arg4, arg5) {
+ const list = this._callbackTable[key];
if (list) {
- var rootInvoker = !list.isInvoking;
+ const rootInvoker = !list.isInvoking;
list.isInvoking = true;
- var callbacks = list.callbacks;
- var targets = list.targets;
- for (var i = 0, len = callbacks.length; i < len; ++i) {
- var callback = callbacks[i];
- if (callback) {
- var target = targets[i];
+ const infos = list.callbackInfos;
+ for (let i = 0, len = infos.length; i < len; ++i) {
+ const info = infos[i];
+ if (info) {
+ let target = info.target;
+ let callback = info.callback;
+ if (info.once) {
+ this.off(key, callback, target);
+ }
+
if (target) {
- callback.call(target, p1, p2, p3, p4, p5);
+ callback.call(target, arg1, arg2, arg3, arg4, arg5);
}
else {
- callback(p1, p2, p3, p4, p5);
+ callback(arg1, arg2, arg3, arg4, arg5);
}
}
}
@@ -269,5 +355,8 @@ CallbacksInvoker.prototype.invoke = function (key, p1, p2, p3, p4, p5) {
}
};
-CallbacksInvoker.CallbacksHandler = CallbacksHandler;
+if (CC_TEST) {
+ cc._Test.CallbacksInvoker = CallbacksInvoker;
+}
+
module.exports = CallbacksInvoker;
diff --git a/cocos2d/core/platform/compiler.js b/cocos2d/core/platform/compiler.js
index f6672674206..c1463e1bd19 100644
--- a/cocos2d/core/platform/compiler.js
+++ b/cocos2d/core/platform/compiler.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/platform/deserialize-compiled.ts b/cocos2d/core/platform/deserialize-compiled.ts
new file mode 100644
index 00000000000..c4415701fe2
--- /dev/null
+++ b/cocos2d/core/platform/deserialize-compiled.ts
@@ -0,0 +1,1099 @@
+/****************************************************************************
+ Copyright (c) present Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import js from './js';
+import ValueType from '../value-types/value-type';
+import Vec2 from '../value-types/vec2';
+import Vec3 from '../value-types/vec3';
+import Vec4 from '../value-types/vec4';
+import Color from '../value-types/color';
+import Size from '../value-types/size';
+import Rect from '../value-types/rect';
+import Quat from '../value-types/quat';
+import Mat4 from '../value-types/mat4';
+// import Attr from './attribute';
+
+/****************************************************************************
+ * BUILT-IN TYPES / CONSTAINTS
+ ****************************************************************************/
+
+const SUPPORT_MIN_FORMAT_VERSION = 1;
+const EMPTY_PLACEHOLDER = 0;
+
+// Used for Data.ValueType.
+// If a value type is not registered in this list, it will be serialized to Data.Class.
+const BuiltinValueTypes: Array = [
+ Vec2, // 0
+ Vec3, // 1
+ Vec4, // 2
+ Quat, // 3
+ Color, // 4
+ Size, // 5
+ Rect, // 6
+ Mat4, // 7
+];
+
+// Used for Data.ValueTypeCreated.
+function BuiltinValueTypeParsers_xyzw (obj: Vec4, data: Array) {
+ obj.x = data[1];
+ obj.y = data[2];
+ obj.z = data[3];
+ obj.w = data[4];
+}
+const BuiltinValueTypeSetters: Array<((obj: ValueType, data: Array) => void)> = [
+ function (obj: Vec2, data: Array) {
+ obj.x = data[1];
+ obj.y = data[2];
+ },
+ function (obj: Vec3, data: Array) {
+ obj.x = data[1];
+ obj.y = data[2];
+ obj.z = data[3];
+ },
+ BuiltinValueTypeParsers_xyzw, // Vec4
+ BuiltinValueTypeParsers_xyzw, // Quat
+ function (obj: Color, data: Array) {
+ obj._val = data[1];
+ },
+ function (obj: Size, data: Array) {
+ obj.width = data[1];
+ obj.height = data[2];
+ },
+ function (obj: Rect, data: Array) {
+ obj.x = data[1];
+ obj.y = data[2];
+ obj.width = data[3];
+ obj.height = data[4];
+ },
+ function (obj: Mat4, data: Array) {
+ Mat4.fromArray(obj, data, 1);
+ }
+];
+
+function serializeBuiltinValueTypes(obj: ValueType): IValueTypeData | null {
+ let ctor = obj.constructor as typeof ValueType;
+ let typeId = BuiltinValueTypes.indexOf(ctor);
+ switch (ctor) {
+ case Vec2:
+ // @ts-ignore
+ return [typeId, obj.x, obj.y];
+ case Vec3:
+ // @ts-ignore
+ return [typeId, obj.x, obj.y, obj.z];
+ case Vec4:
+ case Quat:
+ // @ts-ignore
+ return [typeId, obj.x, obj.y, obj.z, obj.w];
+ case Color:
+ // @ts-ignore
+ return [typeId, obj._val];
+ case Size:
+ // @ts-ignore
+ return [typeId, obj.width, obj.height];
+ case Rect:
+ // @ts-ignore
+ return [typeId, obj.x, obj.y, obj.width, obj.height];
+ case Mat4:
+ // @ts-ignore
+ let res: IValueTypeData = new Array(1 + 16);
+ res[VALUETYPE_SETTER] = typeId;
+ Mat4.toArray(res, obj as Mat4, 1);
+ return res;
+ default:
+ return null;
+ }
+}
+
+// // TODO: Used for Data.TypedArray.
+// const TypedArrays = [
+// Float32Array,
+// Float64Array,
+//
+// Int8Array,
+// Int16Array,
+// Int32Array,
+//
+// Uint8Array,
+// Uint16Array,
+// Uint32Array,
+//
+// Uint8ClampedArray,
+// // BigInt64Array,
+// // BigUint64Array,
+// ];
+
+
+/****************************************************************************
+ * TYPE DECLARATIONS
+ ****************************************************************************/
+
+// Includes Bitwise NOT value.
+// Both T and U have non-negative integer ranges.
+// When the value >= 0 represents T
+// When the value is < 0, it represents ~U. Use ~x to extract the value of U.
+export type Bnot = T|U;
+
+// Combines a boolean and a number into one value.
+// The number must >= 0.
+// When the value >= 0, the boolean is true, the number is value.
+// When the value < 0, the boolean is false, the number is ~value.
+export type BoolAndNum = Bnot;
+
+export type SharedString = string;
+export type Empty = typeof EMPTY_PLACEHOLDER;
+export type StringIndex = number;
+export type InstanceIndex = number;
+export type RootInstanceIndex = InstanceIndex;
+export type NoNativeDep = boolean; // Indicates whether the asset depends on a native asset
+export type RootInfo = BoolAndNum;
+
+// When the value >= 0 represents the string index
+// When the value is < 0, it just represents non-negative integer. Use ~x to extract the value.
+export type StringIndexBnotNumber = Bnot;
+
+// A reverse index used to assign current parsing object to target command buffer so it could be assembled later.
+// Should >= REF.OBJ_OFFSET
+export type ReverseIndex = number;
+
+// Used to index the current object
+export type InstanceBnotReverseIndex = Bnot;
+
+/*@__DROP_PURE_EXPORT__*/
+export const enum DataTypeID {
+
+ // Fields that can be assigned directly, can be values in any JSON, or even a complex JSON array, object (no type).
+ // Contains null, no undefined, JSON does not support serialization of undefined.
+ // This is the only type that supports null, and all other advanced fields are forbidden with null values.
+ // If the value of an object is likely to be null, it needs to exist as a new class,
+ // but the probability of this is very low and will be analyzed below.
+ SimpleType = 0,
+
+ //--------------------------------------------------------------------------
+ // Except Simple, the rest belong to Advanced Type.
+
+ // Rarely will it be NULL, as NULL will be dropped as the default value.
+ InstanceRef,
+
+ // Arrays of exactly equal types.
+ // Arrays will have default values that developers will rarely assign to null manually.
+ Array_InstanceRef,
+ Array_AssetRefByInnerObj,
+
+ // Embedded object
+ // Rarely will it be NULL, as NULL will be dropped as the default value.
+ Class,
+
+ // Existing ValueType (created by the Class constructor).
+ // Developers will rarely manually assign a null.
+ ValueTypeCreated,
+
+ // Resource reference for embedded objects (such as arrays), the value is the index of DEPEND_OBJS.
+ // (The objects in INSTANCES do not need to dynamically resolve resource reference relationships, so there is no need to have the AssetRef type.)
+ AssetRefByInnerObj,
+
+ // Common TypedArray for cc.Node only. Never be null.
+ TRS,
+
+ // // From the point of view of simplified implementation,
+ // // it is not supported to deserialize TypedArray that is initialized to null in the constructor.
+ // // Also, the length of TypedArray cannot be changed.
+ // // Developers will rarely manually assign a null.
+ // TypedArray,
+
+ // ValueType without default value (in arrays, dictionaries).
+ // Developers will rarely manually assign a null.
+ ValueType,
+
+ Array_Class,
+
+ // CustomizedClass embedded in Class
+ CustomizedClass,
+
+ // Universal dictionary with unlimited types of values (except TypedArray)
+ Dict,
+
+ // Universal arrays, of any type (except TypedArray) and can be unequal.
+ // (The editor doesn't seem to have a good way of stopping arrays of unequal types either)
+ Array,
+
+ ARRAY_LENGTH,
+}
+
+export type DataTypes = {
+ [DataTypeID.SimpleType]: number | string | boolean | null | object;
+ [DataTypeID.InstanceRef]: InstanceBnotReverseIndex;
+ [DataTypeID.Array_InstanceRef]: Array;
+ [DataTypeID.Array_AssetRefByInnerObj]: Array;
+ [DataTypeID.Class]: IClassObjectData;
+ [DataTypeID.ValueTypeCreated]: IValueTypeData;
+ [DataTypeID.AssetRefByInnerObj]: number;
+ [DataTypeID.TRS]: ITRSData;
+ // [DataTypeID.TypedArray]: Array;
+ [DataTypeID.ValueType]: IValueTypeData;
+ [DataTypeID.Array_Class]: Array;
+ [DataTypeID.CustomizedClass]: ICustomObjectData;
+ [DataTypeID.Dict]: IDictData;
+ [DataTypeID.Array]: IArrayData;
+};
+
+export type PrimitiveObjectTypeID = (
+ DataTypeID.SimpleType | // SimpleType also includes any pure JSON object
+ DataTypeID.Array |
+ DataTypeID.Array_Class |
+ DataTypeID.Array_AssetRefByInnerObj |
+ DataTypeID.Array_InstanceRef |
+ DataTypeID.Dict
+);
+
+export type AdvancedTypeID = Exclude
+
+
+// Collection of all data types
+export type AnyData = DataTypes[keyof DataTypes];
+
+export type AdvancedData = DataTypes[Exclude];
+
+export type OtherObjectData = ICustomObjectDataContent | Exclude;
+
+// class Index of DataTypeID.CustomizedClass or PrimitiveObjectTypeID
+export type OtherObjectTypeID = Bnot;
+
+export interface Ctor extends Function {
+ new(): T;
+}
+// Includes normal CCClass and fast defined class
+export interface CCClass extends Ctor {
+ __values__: string[]
+}
+export type AnyCtor = Ctor;
+export type AnyCCClass = CCClass;
+
+/**
+ * If the value type is different, different Classes will be generated
+ */
+const CLASS_TYPE = 0;
+const CLASS_KEYS = 1;
+const CLASS_PROP_TYPE_OFFSET = 2;
+export type IClass = [
+ string|AnyCtor,
+ string[],
+ // offset - It is used to specify the correspondence between the elements in CLASS_KEYS and their AdvancedType,
+ // which is only valid for AdvancedType.
+ // When parsing, the type of IClass[CLASS_KEYS][x] is IClass[x + IClass[CLASS_PROP_TYPE_OFFSET]]
+ // When serializing, IClass[CLASS_PROP_TYPE_OFFSET] = CLASS_PROP_TYPE_OFFSET + 1 - (The number of SimpleType)
+ number,
+ // The AdvancedType type corresponding to the property.
+ ...DataTypeID[]
+];
+
+/**
+ * Mask is used to define the properties and types that need to be deserialized.
+ * Instances of the same class may have different Masks due to different default properties removed.
+ */
+const MASK_CLASS = 0;
+export type IMask = [
+ // The index of its Class
+ number,
+ // The indices of the property that needs to be deserialized in IClass, except that the last number represents OFFSET.
+ // All properties before OFFSET are SimpleType, and those starting at OFFSET are AdvancedType.
+ // default is 1
+ ...number[]
+];
+
+const OBJ_DATA_MASK = 0;
+export type IClassObjectData = [
+ // The index of its Mask
+ number,
+ // Starting from 1, the values corresponding to the properties in the Mask
+ ...AnyData[]
+];
+
+export type ICustomObjectDataContent = any;
+
+const CUSTOM_OBJ_DATA_CLASS = 0;
+const CUSTOM_OBJ_DATA_CONTENT = 1;
+export interface ICustomObjectData extends Array {
+ // The index of its Class
+ [CUSTOM_OBJ_DATA_CLASS]: number;
+ // Content
+ [CUSTOM_OBJ_DATA_CONTENT]: ICustomObjectDataContent;
+}
+
+const VALUETYPE_SETTER = 0;
+export type IValueTypeData = [
+ // Predefined parsing function index
+ number,
+ // Starting with 1, the corresponding value in the attributes are followed in order
+ ...number[]
+];
+
+export type ITRSData = [number, number, number, number, number,
+ number, number, number, number, number];
+
+const DICT_JSON_LAYOUT = 0;
+export interface IDictData extends Array {
+ // The raw json object
+ [DICT_JSON_LAYOUT]: any,
+ // key
+ // Shared strings are not considered here, can be defined as CCClass if it is required.
+ [1]: string;
+ // value type
+ // Should not be SimpleType, SimpleType is built directly into DICT_JSON_LAYOUT.
+ [2]: AdvancedTypeID;
+ // value
+ [3]: AdvancedData;
+ // More repeated key values
+ [index: number]: any,
+}
+
+const ARRAY_ITEM_VALUES = 0;
+export type IArrayData = [
+ AnyData[],
+ // types
+ ...DataTypeID[]
+];
+
+// const TYPEDARRAY_TYPE = 0;
+// const TYPEDARRAY_ELEMENTS = 1;
+// export interface ITypedArrayData extends Array {
+// [TYPEDARRAY_TYPE]: number,
+// [TYPEDARRAY_ELEMENTS]: number[],
+// }
+
+/*@__DROP_PURE_EXPORT__*/
+export const enum Refs {
+ EACH_RECORD_LENGTH = 3,
+ OWNER_OFFSET = 0,
+ KEY_OFFSET = 1,
+ TARGET_OFFSET = 2,
+}
+
+export interface IRefs extends Array {
+ // owner
+ // The owner of all the objects in the front is of type object, starting from OFFSET * 3 are of type InstanceIndex
+ [0]: (object | InstanceIndex),
+ // property name
+ [1]?: StringIndexBnotNumber;
+ // target object
+ [2]?: InstanceIndex;
+ // All the following objects are arranged in the order of the first three values,
+ // except that the last number represents OFFSET.
+ [index: number]: any;
+}
+
+/*@__DROP_PURE_EXPORT__*/
+export const enum File {
+ Version = 0,
+ Context = 0,
+
+ SharedUuids,
+ SharedStrings,
+ SharedClasses,
+ SharedMasks,
+
+ Instances,
+ InstanceTypes,
+
+ Refs,
+
+ DependObjs,
+ DependKeys,
+ DependUuidIndices,
+
+ ARRAY_LENGTH,
+}
+
+// Main file structure
+export interface IFileData extends Array {
+ // version
+ [File.Version]: number | FileInfo | any;
+
+ // Shared data area, the higher the number of references, the higher the position
+
+ [File.SharedUuids]: SharedString[] | Empty; // Shared uuid strings for dependent assets
+ [File.SharedStrings]: SharedString[] | Empty;
+ [File.SharedClasses]: (IClass|string|AnyCCClass)[];
+ [File.SharedMasks]: IMask[] | Empty; // Shared Object layouts for IClassObjectData
+
+ // Data area
+
+ // A one-dimensional array to represent object datas, layout is [...IClassObjectData[], ...OtherObjectData[], RootInfo]
+ // If the last element is not RootInfo(number), the first element will be the root object to return and it doesn't have native asset
+ [File.Instances]: (IClassObjectData|OtherObjectData|RootInfo)[];
+ [File.InstanceTypes]: OtherObjectTypeID[] | Empty;
+ // Object references infomation
+ [File.Refs]: IRefs | Empty;
+
+ // Result area
+
+ // Asset-dependent objects that are deserialized and parsed into object arrays
+ [File.DependObjs]: (object|InstanceIndex)[];
+ // Asset-dependent key name or array index
+ [File.DependKeys]: (StringIndexBnotNumber|string)[];
+ // UUID of dependent assets
+ [File.DependUuidIndices]: (StringIndex|string)[];
+}
+
+// type Body = Pick
+type Shared = Pick
+const PACKED_SECTIONS = File.Instances;
+export interface IPackedFileData extends Shared {
+ [PACKED_SECTIONS]: IFileData[];
+}
+
+interface ICustomHandler {
+ result: Details,
+ customEnv: any,
+}
+type ClassFinder = {
+ (type: string): AnyCtor;
+ // // for editor
+ // onDereferenced: (curOwner: object, curPropName: string, newOwner: object, newPropName: string) => void;
+};
+interface IOptions extends Partial {
+ classFinder?: ClassFinder;
+ _version?: number;
+}
+interface ICustomClass {
+ _deserialize: (content: any, context: ICustomHandler) => void;
+}
+
+/****************************************************************************
+ * IMPLEMENTS
+ ****************************************************************************/
+
+/**
+ * !#en Contains meta information collected during deserialization
+ * !#zh 包含反序列化后附带的元信息
+ * @class Details
+ */
+class Details {
+ /**
+ * the obj list whose field needs to load asset by uuid
+ * @property {Object[]} uuidObjList
+ */
+ uuidObjList: IFileData[File.DependObjs] | null = null;
+ /**
+ * the corresponding field name which referenced to the asset
+ * @property {(String|Number)[]} uuidPropList
+ */
+ uuidPropList: IFileData[File.DependKeys] | null = null;
+ /**
+ * list of the depends assets' uuid
+ * @property {String[]} uuidList
+ */
+ uuidList: IFileData[File.DependUuidIndices] | null = null;
+
+ static pool = new js.Pool(function (obj) {
+ obj.reset();
+ }, 5);
+
+ /**
+ * @method init
+ * @param {Object} data
+ */
+ init (data: IFileData) {
+ this.uuidObjList = data[File.DependObjs];
+ this.uuidPropList = data[File.DependKeys];
+ this.uuidList = data[File.DependUuidIndices];
+ }
+
+ /**
+ * @method reset
+ */
+ reset () {
+ this.uuidList = null;
+ this.uuidObjList = null;
+ this.uuidPropList = null;
+ };
+
+ /**
+ * @method push
+ * @param {Object} obj
+ * @param {String} propName
+ * @param {String} uuid
+ */
+ push (obj: object, propName: string, uuid: string) {
+ (this.uuidObjList as object[]).push(obj);
+ (this.uuidPropList as string[]).push(propName);
+ (this.uuidList as string[]).push(uuid);
+ };
+}
+Details.pool.get = function () {
+ return this._get() || new Details();
+};
+if (CC_EDITOR || CC_TEST) {
+ // @ts-ignore
+ Details.prototype.assignAssetsBy = function (getter: (uuid: string) => any) {
+ for (var i = 0, len = (this.uuidList as string[]).length; i < len; i++) {
+ var obj = (this.uuidObjList as object)[i];
+ var prop = (this.uuidPropList as any[])[i];
+ var uuid = (this.uuidList as string[])[i];
+ obj[prop] = getter(uuid as string);
+ }
+ };
+}
+
+function dereference(refs: IRefs, instances: IFileData[File.Instances], strings: IFileData[File.SharedStrings]): void {
+ let dataLength = refs.length - 1;
+ let i = 0;
+ // owner is object
+ let instanceOffset: number = refs[dataLength] * Refs.EACH_RECORD_LENGTH;
+ for (; i < instanceOffset; i += Refs.EACH_RECORD_LENGTH) {
+ const owner = refs[i] as any;
+
+ const target = instances[refs[i + Refs.TARGET_OFFSET]];
+ const keyIndex = refs[i + Refs.KEY_OFFSET] as StringIndexBnotNumber;
+ if (keyIndex >= 0) {
+ owner[strings[keyIndex]] = target;
+ }
+ else {
+ owner[~keyIndex] = target;
+ }
+ }
+ // owner is instance index
+ for (; i < dataLength; i += Refs.EACH_RECORD_LENGTH) {
+ const owner = instances[refs[i]] as any;
+
+ const target = instances[refs[i + Refs.TARGET_OFFSET]];
+ const keyIndex = refs[i + Refs.KEY_OFFSET] as StringIndexBnotNumber;
+ if (keyIndex >= 0) {
+ owner[strings[keyIndex]] = target;
+ }
+ else {
+ owner[~keyIndex] = target;
+ }
+ }
+}
+
+//
+
+function deserializeCCObject (data: IFileData, objectData: IClassObjectData) {
+ let mask = data[File.SharedMasks][objectData[OBJ_DATA_MASK]];
+ let clazz = mask[MASK_CLASS];
+ let ctor = clazz[CLASS_TYPE] as Exclude;
+ // if (!ctor) {
+ // return null;
+ // }
+
+ let obj = new ctor();
+
+ let keys = clazz[CLASS_KEYS];
+ let classTypeOffset = clazz[CLASS_PROP_TYPE_OFFSET];
+ let maskTypeOffset = mask[mask.length - 1];
+
+ // parse simple type
+ let i = MASK_CLASS + 1;
+ for (; i < maskTypeOffset; ++i) {
+ let key = keys[mask[i]];
+ obj[key] = objectData[i];
+ }
+
+ // parse advanced type
+ for (; i < objectData.length; ++i) {
+ let key = keys[mask[i]];
+ let type = clazz[mask[i] + classTypeOffset];
+ let op = ASSIGNMENTS[type];
+ op(data, obj, key, objectData[i]);
+ }
+
+ return obj;
+}
+
+function deserializeCustomCCObject (data: IFileData, ctor: Ctor, value: ICustomObjectDataContent) {
+ let obj = new ctor();
+ if (obj._deserialize) {
+ obj._deserialize(value, data[File.Context]);
+ }
+ else {
+ cc.errorID(5303, js.getClassName(ctor));
+ }
+ return obj;
+}
+
+// Parse Functions
+
+type ParseFunction = (data: IFileData, owner: any, key: string, value: AnyData) => void;
+
+function assignSimple (data: IFileData, owner: any, key: string, value: DataTypes[DataTypeID.SimpleType]) {
+ owner[key] = value;
+}
+
+function assignInstanceRef (data: IFileData, owner: any, key: string, value: InstanceBnotReverseIndex) {
+ if (value >= 0) {
+ owner[key] = data[File.Instances][value];
+ }
+ else {
+ (data[File.Refs] as IRefs)[(~value) * Refs.EACH_RECORD_LENGTH] = owner;
+ }
+}
+
+function genArrayParser (parser: ParseFunction): ParseFunction {
+ return function (data: IFileData, owner: any, key: string, value: Array) {
+ owner[key] = value;
+ for (let i = 0; i < value.length; ++i) {
+ // @ts-ignore
+ parser(data, value, i, value[i]);
+ }
+ };
+}
+
+function parseAssetRefByInnerObj (data: IFileData, owner: any, key: string, value: number) {
+ owner[key] = null;
+ data[File.DependObjs][value] = owner;
+}
+
+function parseClass (data: IFileData, owner: any, key: string, value: IClassObjectData) {
+ owner[key] = deserializeCCObject(data, value);
+}
+
+function parseCustomClass (data: IFileData, owner: any, key: string, value: ICustomObjectData) {
+ let ctor = data[File.SharedClasses][value[CUSTOM_OBJ_DATA_CLASS]] as CCClass;
+ owner[key] = deserializeCustomCCObject(data, ctor, value[CUSTOM_OBJ_DATA_CONTENT]);
+}
+
+function parseValueTypeCreated (data: IFileData, owner: any, key: string, value: IValueTypeData) {
+ BuiltinValueTypeSetters[value[VALUETYPE_SETTER]](owner[key], value);
+}
+
+function parseValueType (data: IFileData, owner: any, key: string, value: IValueTypeData) {
+ let val: ValueType = new BuiltinValueTypes[value[VALUETYPE_SETTER]]();
+ BuiltinValueTypeSetters[value[VALUETYPE_SETTER]](val, value);
+ owner[key] = val;
+}
+
+function parseTRS (data: IFileData, owner: any, key: string, value: ITRSData) {
+ let typedArray = owner[key] as (Float32Array | Float64Array);
+ typedArray.set(value);
+}
+
+function parseDict (data: IFileData, owner: any, key: string, value: IDictData) {
+ let dict = value[DICT_JSON_LAYOUT];
+ owner[key] = dict;
+ for (let i = DICT_JSON_LAYOUT + 1; i < value.length; i += 3) {
+ let key = value[i] as string;
+ let type = value[i + 1] as DataTypeID;
+ let subValue = value[i + 2] as AnyData;
+ let op = ASSIGNMENTS[type];
+ op(data, dict, key, subValue);
+ }
+}
+
+function parseArray (data: IFileData, owner: any, key: string, value: IArrayData) {
+ let array = value[ARRAY_ITEM_VALUES];
+ owner[key] = array;
+ for (let i = 0; i < array.length; ++i) {
+ let subValue = array[i] as AnyData;
+ let type = value[i + 1] as DataTypeID;
+ if (type !== DataTypeID.SimpleType) {
+ let op = ASSIGNMENTS[type];
+ // @ts-ignore
+ op(data, array, i, subValue);
+ }
+ }
+}
+
+// function parseTypedArray (data: IFileData, owner: any, key: string, value: ITypedArrayData) {
+// let val: ValueType = new TypedArrays[value[TYPEDARRAY_TYPE]]();
+// BuiltinValueTypeSetters[value[VALUETYPE_SETTER]](val, value);
+// // obj = new window[serialized.ctor](array.length);
+// // for (let i = 0; i < array.length; ++i) {
+// // obj[i] = array[i];
+// // }
+// // return obj;
+// owner[key] = val;
+// }
+
+const ASSIGNMENTS = new Array(DataTypeID.ARRAY_LENGTH);
+ASSIGNMENTS[DataTypeID.SimpleType] = assignSimple; // Only be used in the instances array
+ASSIGNMENTS[DataTypeID.InstanceRef] = assignInstanceRef;
+ASSIGNMENTS[DataTypeID.Array_InstanceRef] = genArrayParser(assignInstanceRef);
+ASSIGNMENTS[DataTypeID.Array_AssetRefByInnerObj] = genArrayParser(parseAssetRefByInnerObj);
+ASSIGNMENTS[DataTypeID.Class] = parseClass;
+ASSIGNMENTS[DataTypeID.ValueTypeCreated] = parseValueTypeCreated;
+ASSIGNMENTS[DataTypeID.AssetRefByInnerObj] = parseAssetRefByInnerObj;
+ASSIGNMENTS[DataTypeID.TRS] = parseTRS;
+ASSIGNMENTS[DataTypeID.ValueType] = parseValueType;
+ASSIGNMENTS[DataTypeID.Array_Class] = genArrayParser(parseClass);
+ASSIGNMENTS[DataTypeID.CustomizedClass] = parseCustomClass;
+ASSIGNMENTS[DataTypeID.Dict] = parseDict;
+ASSIGNMENTS[DataTypeID.Array] = parseArray;
+// ASSIGNMENTS[DataTypeID.TypedArray] = parseTypedArray;
+
+
+
+function parseInstances (data: IFileData): RootInstanceIndex {
+ let instances = data[File.Instances];
+ let instanceTypes = data[File.InstanceTypes];
+ let instanceTypesLen = instanceTypes === EMPTY_PLACEHOLDER ? 0 : (instanceTypes as OtherObjectTypeID[]).length;
+ let rootIndex = instances[instances.length - 1];
+ let normalObjectCount = instances.length - instanceTypesLen;
+ if (typeof rootIndex !== 'number') {
+ rootIndex = 0;
+ }
+ else {
+ if (rootIndex < 0) {
+ rootIndex = ~rootIndex;
+ }
+ --normalObjectCount;
+ }
+
+ // DataTypeID.Class
+
+ let insIndex = 0;
+ for (; insIndex < normalObjectCount; ++insIndex) {
+ instances[insIndex] = deserializeCCObject(data, instances[insIndex] as IClassObjectData);
+ }
+
+ let classes = data[File.SharedClasses];
+ for (let typeIndex = 0; typeIndex < instanceTypesLen; ++typeIndex, ++insIndex) {
+ let type = instanceTypes[typeIndex] as OtherObjectTypeID;
+ let eachData = instances[insIndex];
+ if (type >= 0) {
+
+ // class index for DataTypeID.CustomizedClass
+
+ let ctor = classes[type] as CCClass; // class
+ instances[insIndex] = deserializeCustomCCObject(data, ctor, eachData as ICustomObjectDataContent);
+ }
+ else {
+
+ // Other
+
+ type = (~type) as PrimitiveObjectTypeID;
+ let op = ASSIGNMENTS[type];
+ // @ts-ignore
+ op(data, instances, insIndex, eachData);
+ }
+ }
+
+ return rootIndex;
+}
+
+// const DESERIALIZE_AS = Attr.DELIMETER + 'deserializeAs';
+// function deserializeAs(klass: AnyCCClass, klassLayout: IClass) {
+// var attrs = Attr.getClassAttrs(klass);
+// let keys = klassLayout[CLASS_KEYS];
+// for (let i = 0; i < keys.length; ++i) {
+// let newKey = attrs[keys[i] + DESERIALIZE_AS];
+// if (newKey) {
+// // @ts-ignore
+// if (keys.includes(newKey)) {
+// // %s cannot be deserialized by property %s because %s was also present in the serialized data.
+// cc.warnID(, newKey, keys[i], newKey);
+// }
+// else {
+// keys[i] = newKey;
+// }
+// }
+// }
+// }
+
+function getMissingClass (hasCustomFinder, type) {
+ if (!hasCustomFinder) {
+ // @ts-ignore
+ deserialize.reportMissingClass(type);
+ }
+ return Object;
+}
+function doLookupClass(classFinder, type: string, container: any[], index: number, silent: boolean, hasCustomFinder) {
+ let klass = classFinder(type);
+ if (!klass) {
+ // if (klass.__FSA__) {
+ // deserializeAs(klass, klassLayout as IClass);
+ // }
+ if (silent) {
+ // generate a lazy proxy for ctor
+ container[index] = (function (container, index, type) {
+ return function proxy () {
+ let klass = classFinder(type) || getMissingClass(hasCustomFinder, type);
+ container[index] = klass;
+ return new klass();
+ };
+ })(container, index, type);
+ return;
+ }
+ else {
+ klass = getMissingClass(hasCustomFinder, type);
+ }
+ }
+ container[index] = klass;
+}
+
+function lookupClasses (data: IPackedFileData, silent: boolean, customFinder?: ClassFinder) {
+ let classFinder = customFinder || js._getClassById;
+ let classes = data[File.SharedClasses];
+ for (let i = 0; i < classes.length; ++i) {
+ let klassLayout = classes[i];
+ if (typeof klassLayout !== 'string') {
+ if (CC_DEBUG) {
+ if (typeof klassLayout[CLASS_TYPE] === 'function') {
+ throw new Error('Can not deserialize the same JSON data again.');
+ }
+ }
+ let type: string = klassLayout[CLASS_TYPE];
+ doLookupClass(classFinder, type, klassLayout as IClass, CLASS_TYPE, silent, customFinder);
+ }
+ else {
+ doLookupClass(classFinder, klassLayout, classes, i, silent, customFinder);
+ }
+ }
+}
+
+function cacheMasks (data: IPackedFileData) {
+ let masks = data[File.SharedMasks];
+ if (masks) {
+ let classes = data[File.SharedClasses];
+ for (let i = 0; i < masks.length; ++i) {
+ let mask = masks[i];
+ // @ts-ignore
+ mask[MASK_CLASS] = classes[mask[MASK_CLASS]];
+ }
+ }
+}
+
+function parseResult (data: IFileData) {
+ let instances = data[File.Instances];
+ let sharedStrings = data[File.SharedStrings];
+ let dependSharedUuids = data[File.SharedUuids];
+
+ let dependObjs = data[File.DependObjs];
+ let dependKeys = data[File.DependKeys];
+ let dependUuids = data[File.DependUuidIndices];
+
+ for (let i = 0; i < dependObjs.length; ++i) {
+ let obj: any = dependObjs[i];
+ if (typeof obj === 'number') {
+ dependObjs[i] = instances[obj];
+ }
+ else {
+ // assigned by DataTypeID.AssetRefByInnerObj or added by Details object directly in _deserialize
+ }
+ let key: any = dependKeys[i];
+ if (typeof key === 'number') {
+ if (key >= 0) {
+ key = sharedStrings[key];
+ }
+ else {
+ key = ~key;
+ }
+ dependKeys[i] = key;
+ }
+ else {
+ // added by Details object directly in _deserialize
+ }
+ let uuid = dependUuids[i];
+ if (typeof uuid === 'number') {
+ dependUuids[i] = (dependSharedUuids as SharedString[])[uuid as StringIndex];
+ }
+ else {
+ // added by Details object directly in _deserialize
+ }
+ }
+}
+
+export default function deserialize (data: IFileData, details: Details, options?: IOptions): object {
+ // @ts-ignore
+ if (CC_EDITOR && Buffer.isBuffer(data)) {
+ // @ts-ignore
+ data = data.toString();
+ }
+ if (typeof data === 'string') {
+ data = JSON.parse(data);
+ }
+ let borrowDetails = !details;
+ details = details || Details.pool.get();
+ details.init(data);
+ options = options || {};
+
+ let version = data[File.Version];
+ let preprocessed = false;
+ if (typeof version === 'object') {
+ preprocessed = version.preprocessed;
+ version = version.version;
+ }
+ if (version < SUPPORT_MIN_FORMAT_VERSION) {
+ throw new Error(cc.debug.getError(5304, version));
+ }
+ options._version = version;
+ options.result = details;
+ data[File.Context] = options;
+
+ if (!preprocessed) {
+ lookupClasses(data, false, options.classFinder);
+ cacheMasks(data);
+ }
+
+ cc.game._isCloning = true;
+ let instances = data[File.Instances];
+ let rootIndex = parseInstances(data);
+ cc.game._isCloning = false;
+
+ if (data[File.Refs]) {
+ dereference(data[File.Refs] as IRefs, instances, data[File.SharedStrings]);
+ }
+
+ parseResult(data);
+
+ if (borrowDetails) {
+ Details.pool.put(details);
+ }
+
+ return instances[rootIndex];
+};
+
+deserialize.Details = Details;
+
+class FileInfo {
+ declare version: number;
+ preprocessed = true;
+ constructor (version: number) {
+ this.version = version;
+ }
+}
+
+export function unpackJSONs (data: IPackedFileData, classFinder?: ClassFinder): IFileData[] {
+ if (data[File.Version] < SUPPORT_MIN_FORMAT_VERSION) {
+ throw new Error(cc.debug.getError(5304, data[File.Version]));
+ }
+ lookupClasses(data, true, classFinder);
+ cacheMasks(data);
+
+ let version = new FileInfo(data[File.Version]);
+ let sharedUuids = data[File.SharedUuids];
+ let sharedStrings = data[File.SharedStrings];
+ let sharedClasses = data[File.SharedClasses];
+ let sharedMasks = data[File.SharedMasks];
+
+ let sections = data[PACKED_SECTIONS];
+ for (let i = 0; i < sections.length; ++i) {
+ sections[i].unshift(version, sharedUuids, sharedStrings, sharedClasses, sharedMasks);
+ }
+ return sections;
+}
+
+export function packCustomObjData (type: string, data: IClassObjectData|OtherObjectData): IFileData {
+ return [
+ SUPPORT_MIN_FORMAT_VERSION, EMPTY_PLACEHOLDER, EMPTY_PLACEHOLDER,
+ [type],
+ EMPTY_PLACEHOLDER,
+ [data],
+ [0],
+ EMPTY_PLACEHOLDER, [], [], []
+ ];
+}
+
+export function hasNativeDep (data: IFileData): boolean {
+ let instances = data[File.Instances];
+ let rootInfo = instances[instances.length - 1];
+ if (typeof rootInfo !== 'number') {
+ return false;
+ }
+ else {
+ return rootInfo < 0;
+ }
+}
+
+if (CC_PREVIEW) {
+ deserialize.isCompiledJson = function (json: object): boolean {
+ if (Array.isArray(json)) {
+ let version = json[0];
+ // array[0] will not be a number in the editor version
+ return typeof version === 'number' || version instanceof FileInfo;
+ }
+ else {
+ return false;
+ }
+ };
+}
+
+export function getDependUuidList (json: IFileData): Array {
+ let sharedUuids = json[File.SharedUuids];
+ return json[File.DependUuidIndices].map(index => sharedUuids[index]);
+}
+
+if (CC_EDITOR || CC_TEST) {
+ cc._deserializeCompiled = deserialize;
+ deserialize.macros = {
+ EMPTY_PLACEHOLDER,
+ CUSTOM_OBJ_DATA_CLASS,
+ CUSTOM_OBJ_DATA_CONTENT,
+ CLASS_TYPE,
+ CLASS_KEYS,
+ CLASS_PROP_TYPE_OFFSET,
+ MASK_CLASS,
+ OBJ_DATA_MASK,
+ DICT_JSON_LAYOUT,
+ ARRAY_ITEM_VALUES,
+ PACKED_SECTIONS,
+ };
+ deserialize._BuiltinValueTypes = BuiltinValueTypes;
+ deserialize._serializeBuiltinValueTypes = serializeBuiltinValueTypes;
+}
+
+if (CC_TEST) {
+ cc._Test.deserializeCompiled = {
+ deserialize,
+ dereference,
+ deserializeCCObject,
+ deserializeCustomCCObject,
+ parseInstances,
+ parseResult,
+ cacheMasks,
+ File: {
+ Version: File.Version,
+ Context: File.Context,
+ SharedUuids: File.SharedUuids,
+ SharedStrings: File.SharedStrings,
+ SharedClasses: File.SharedClasses,
+ SharedMasks: File.SharedMasks,
+ Instances: File.Instances,
+ InstanceTypes: File.InstanceTypes,
+ Refs: File.Refs,
+ DependObjs: File.DependObjs,
+ DependKeys: File.DependKeys,
+ DependUuidIndices: File.DependUuidIndices,
+ // ArrayLength: File.ArrayLength,
+ },
+ DataTypeID: {
+ SimpleType: DataTypeID.SimpleType,
+ InstanceRef: DataTypeID.InstanceRef,
+ Array_InstanceRef: DataTypeID.Array_InstanceRef,
+ Array_AssetRefByInnerObj: DataTypeID.Array_AssetRefByInnerObj,
+ Class: DataTypeID.Class,
+ ValueTypeCreated: DataTypeID.ValueTypeCreated,
+ AssetRefByInnerObj: DataTypeID.AssetRefByInnerObj,
+ TRS: DataTypeID.TRS,
+ ValueType: DataTypeID.ValueType,
+ Array_Class: DataTypeID.Array_Class,
+ CustomizedClass: DataTypeID.CustomizedClass,
+ Dict: DataTypeID.Dict,
+ Array: DataTypeID.Array,
+ // TypedArray: DataTypeID.TypedArray,
+ },
+ BuiltinValueTypes,
+ unpackJSONs,
+ };
+}
diff --git a/cocos2d/core/platform/deserialize-editor.js b/cocos2d/core/platform/deserialize-editor.js
new file mode 100644
index 00000000000..adff3a62bdd
--- /dev/null
+++ b/cocos2d/core/platform/deserialize-editor.js
@@ -0,0 +1,747 @@
+/****************************************************************************
+ Copyright (c) 2013-2016 Chukong Technologies Inc.
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+var js = require('./js');
+var Attr = require('./attribute');
+var CCClass = require('./CCClass');
+var misc = require('../utils/misc');
+
+import deserializeCompiled from './deserialize-compiled';
+
+// HELPERS
+
+/**
+ * !#en Contains information collected during deserialization
+ * !#zh 包含反序列化时的一些信息
+ * @class Details
+ *
+ */
+var Details = function () {
+ /**
+ * list of the depends assets' uuid
+ * @property {String[]} uuidList
+ */
+ this.uuidList = [];
+ /**
+ * the obj list whose field needs to load asset by uuid
+ * @property {Object[]} uuidObjList
+ */
+ this.uuidObjList = [];
+ /**
+ * the corresponding field name which referenced to the asset
+ * @property {String[]} uuidPropList
+ */
+ this.uuidPropList = [];
+};
+/**
+ * @method reset
+ */
+Details.prototype.reset = function () {
+ this.uuidList.length = 0;
+ this.uuidObjList.length = 0;
+ this.uuidPropList.length = 0;
+};
+if (CC_EDITOR || CC_TEST) {
+ Details.prototype.assignAssetsBy = function (getter) {
+ for (var i = 0, len = this.uuidList.length; i < len; i++) {
+ var uuid = this.uuidList[i];
+ var obj = this.uuidObjList[i];
+ var prop = this.uuidPropList[i];
+ obj[prop] = getter(uuid);
+ }
+ };
+}
+// /**
+// * @method getUuidOf
+// * @param {Object} obj
+// * @param {String} propName
+// * @return {String}
+// */
+// Details.prototype.getUuidOf = function (obj, propName) {
+// for (var i = 0; i < this.uuidObjList.length; i++) {
+// if (this.uuidObjList[i] === obj && this.uuidPropList[i] === propName) {
+// return this.uuidList[i];
+// }
+// }
+// return "";
+// };
+/**
+ * @method push
+ * @param {Object} obj
+ * @param {String} propName
+ * @param {String} uuid
+ */
+Details.prototype.push = function (obj, propName, uuid) {
+ this.uuidList.push(uuid);
+ this.uuidObjList.push(obj);
+ this.uuidPropList.push(propName);
+};
+
+Details.pool = new js.Pool(function (obj) {
+ obj.reset();
+}, 10);
+
+Details.pool.get = function () {
+ return this._get() || new Details();
+};
+
+// IMPLEMENT OF DESERIALIZATION
+
+var _Deserializer = (function () {
+ function _Deserializer(result, classFinder, customEnv, ignoreEditorOnly) {
+ this.result = result;
+ this.customEnv = customEnv;
+ this.deserializedList = [];
+ this.deserializedData = null;
+ this._classFinder = classFinder;
+ if (!CC_BUILD) {
+ this._ignoreEditorOnly = ignoreEditorOnly;
+ }
+ this._idList = [];
+ this._idObjList = [];
+ this._idPropList = [];
+ }
+
+ function _dereference (self) {
+ // 这里不采用遍历反序列化结果的方式,因为反序列化的结果如果引用到复杂的外部库,很容易堆栈溢出。
+ var deserializedList = self.deserializedList;
+ var idPropList = self._idPropList;
+ var idList = self._idList;
+ var idObjList = self._idObjList;
+ var onDereferenced = self._classFinder && self._classFinder.onDereferenced;
+ var i, propName, id;
+ if (CC_EDITOR && onDereferenced) {
+ for (i = 0; i < idList.length; i++) {
+ propName = idPropList[i];
+ id = idList[i];
+ idObjList[i][propName] = deserializedList[id];
+ onDereferenced(deserializedList, id, idObjList[i], propName);
+ }
+ }
+ else {
+ for (i = 0; i < idList.length; i++) {
+ propName = idPropList[i];
+ id = idList[i];
+ idObjList[i][propName] = deserializedList[id];
+ }
+ }
+ }
+
+ var prototype = _Deserializer.prototype;
+
+ prototype.deserialize = function (jsonObj) {
+ if (Array.isArray(jsonObj)) {
+ var jsonArray = jsonObj;
+ var refCount = jsonArray.length;
+ this.deserializedList.length = refCount;
+ // deserialize
+ for (var i = 0; i < refCount; i++) {
+ if (jsonArray[i]) {
+ if (CC_EDITOR || CC_TEST) {
+ this.deserializedList[i] = this._deserializeObject(jsonArray[i], this.deserializedList, '' + i);
+ }
+ else {
+ this.deserializedList[i] = this._deserializeObject(jsonArray[i]);
+ }
+ }
+ }
+ this.deserializedData = refCount > 0 ? this.deserializedList[0] : [];
+
+ //// callback
+ //for (var j = 0; j < refCount; j++) {
+ // if (referencedList[j].onAfterDeserialize) {
+ // referencedList[j].onAfterDeserialize();
+ // }
+ //}
+ }
+ else {
+ this.deserializedList.length = 1;
+ if (CC_EDITOR || CC_TEST) {
+ this.deserializedData = jsonObj ? this._deserializeObject(jsonObj, this.deserializedList, '0') : null;
+ }
+ else {
+ this.deserializedData = jsonObj ? this._deserializeObject(jsonObj) : null;
+ }
+ this.deserializedList[0] = this.deserializedData;
+
+ //// callback
+ //if (deserializedData.onAfterDeserialize) {
+ // deserializedData.onAfterDeserialize();
+ //}
+ }
+
+ // dereference
+ _dereference(this);
+
+ return this.deserializedData;
+ };
+
+ ///**
+ // * @param {Object} serialized - The obj to deserialize, must be non-nil
+ // * @param {Object} [owner] - debug only
+ // * @param {String} [propName] - debug only
+ // */
+ prototype._deserializeObject = function (serialized, owner, propName) {
+ var prop;
+ var obj = null; // the obj to return
+ var klass = null;
+ var type = serialized.__type__;
+ if (type === 'TypedArray') {
+ var array = serialized.array;
+ obj = new window[serialized.ctor](array.length);
+ for (let i = 0; i < array.length; ++i) {
+ obj[i] = array[i];
+ }
+ return obj;
+ }
+ else if (type) {
+
+ // Type Object (including CCClass)
+
+ klass = this._classFinder(type, serialized, owner, propName);
+ if (!klass) {
+ var notReported = this._classFinder === js._getClassById;
+ if (notReported) {
+ deserialize.reportMissingClass(type);
+ }
+ return null;
+ }
+
+ // instantiate a new object
+ obj = new klass();
+
+ if (obj._deserialize) {
+ obj._deserialize(serialized.content, this);
+ return obj;
+ }
+ if (cc.Class._isCCClass(klass)) {
+ _deserializeFireClass(this, obj, serialized, klass);
+ }
+ else {
+ this._deserializeTypedObject(obj, serialized, klass);
+ }
+ }
+ else if ( !Array.isArray(serialized) ) {
+
+ // embedded primitive javascript object
+
+ obj = {};
+ this._deserializePrimitiveObject(obj, serialized);
+ }
+ else {
+
+ // Array
+
+ obj = new Array(serialized.length);
+
+ for (let i = 0; i < serialized.length; i++) {
+ prop = serialized[i];
+ if (typeof prop === 'object' && prop) {
+ this._deserializeObjField(obj, prop, '' + i);
+ }
+ else {
+ obj[i] = prop;
+ }
+ }
+ }
+ return obj;
+ };
+
+ // 和 _deserializeObject 不同的地方在于会判断 id 和 uuid
+ prototype._deserializeObjField = function (obj, jsonObj, propName) {
+ var id = jsonObj.__id__;
+ if (id === undefined) {
+ var uuid = jsonObj.__uuid__;
+ if (uuid) {
+ this.result.push(obj, propName, uuid);
+ }
+ else {
+ if (CC_EDITOR || CC_TEST) {
+ obj[propName] = this._deserializeObject(jsonObj, obj, propName);
+ }
+ else {
+ obj[propName] = this._deserializeObject(jsonObj);
+ }
+ }
+ }
+ else {
+ var dObj = this.deserializedList[id];
+ if (dObj) {
+ obj[propName] = dObj;
+ }
+ else {
+ this._idList.push(id);
+ this._idObjList.push(obj);
+ this._idPropList.push(propName);
+ }
+ }
+ };
+
+ prototype._deserializePrimitiveObject = function (instance, serialized) {
+ for (var propName in serialized) {
+ if (serialized.hasOwnProperty(propName)) {
+ var prop = serialized[propName];
+ if (typeof prop !== 'object') {
+ if (propName !== '__type__'/* && k != '__id__'*/) {
+ instance[propName] = prop;
+ }
+ }
+ else {
+ if (prop) {
+ this._deserializeObjField(instance, prop, propName);
+ }
+ else {
+ instance[propName] = null;
+ }
+ }
+
+ }
+ }
+ };
+
+ // function _compileTypedObject (accessor, klass, ctorCode) {
+ // if (klass === cc.Vec2) {
+ // return `{` +
+ // `o${accessor}.x=prop.x||0;` +
+ // `o${accessor}.y=prop.y||0;` +
+ // `}`;
+ // }
+ // else if (klass === cc.Color) {
+ // return `{` +
+ // `o${accessor}.r=prop.r||0;` +
+ // `o${accessor}.g=prop.g||0;` +
+ // `o${accessor}.b=prop.b||0;` +
+ // `o${accessor}.a=(prop.a===undefined?255:prop.a);` +
+ // `}`;
+ // }
+ // else if (klass === cc.Size) {
+ // return `{` +
+ // `o${accessor}.width=prop.width||0;` +
+ // `o${accessor}.height=prop.height||0;` +
+ // `}`;
+ // }
+ // else {
+ // return `s._deserializeTypedObject(o${accessor},prop,${ctorCode});`;
+ // }
+ // }
+
+ // deserialize ValueType
+ prototype._deserializeTypedObject = function (instance, serialized, klass) {
+ if (klass === cc.Vec2) {
+ instance.x = serialized.x || 0;
+ instance.y = serialized.y || 0;
+ return;
+ }
+ else if (klass === cc.Vec3) {
+ instance.x = serialized.x || 0;
+ instance.y = serialized.y || 0;
+ instance.z = serialized.z || 0;
+ return;
+ }
+ else if (klass === cc.Color) {
+ instance.r = serialized.r || 0;
+ instance.g = serialized.g || 0;
+ instance.b = serialized.b || 0;
+ var a = serialized.a;
+ instance.a = (a === undefined ? 255 : a);
+ return;
+ }
+ else if (klass === cc.Size) {
+ instance.width = serialized.width || 0;
+ instance.height = serialized.height || 0;
+ return;
+ }
+
+ var DEFAULT = Attr.DELIMETER + 'default';
+ var attrs = Attr.getClassAttrs(klass);
+ var fastDefinedProps = klass.__props__ ||
+ Object.keys(instance); // 遍历 instance,如果具有类型,才不会把 __type__ 也读进来
+ for (var i = 0; i < fastDefinedProps.length; i++) {
+ var propName = fastDefinedProps[i];
+ var value = serialized[propName];
+ if (value === undefined || !serialized.hasOwnProperty(propName)) {
+ // not serialized,
+ // recover to default value in ValueType, because eliminated properties equals to
+ // its default value in ValueType, not default value in user class
+ value = CCClass.getDefault(attrs[propName + DEFAULT]);
+ }
+
+ if (typeof value !== 'object') {
+ instance[propName] = value;
+ }
+ else if (value) {
+ this._deserializeObjField(instance, value, propName);
+ }
+ else {
+ instance[propName] = null;
+ }
+ }
+ };
+
+ function compileObjectTypeJit (sources, defaultValue, accessorToSet, propNameLiteralToSet, assumeHavePropIfIsValue) {
+ if (defaultValue instanceof cc.ValueType) {
+ // fast case
+ if (!assumeHavePropIfIsValue) {
+ sources.push('if(prop){');
+ }
+ var ctorCode = js.getClassName(defaultValue);
+ sources.push(`s._deserializeTypedObject(o${accessorToSet},prop,${ctorCode});`);
+ if (!assumeHavePropIfIsValue) {
+ sources.push('}else o' + accessorToSet + '=null;');
+ }
+ }
+ else {
+ sources.push('if(prop){');
+ sources.push('s._deserializeObjField(o,prop,' +
+ propNameLiteralToSet +
+ ');');
+ sources.push('}else o' + accessorToSet + '=null;');
+ }
+ }
+
+ var compileDeserialize = CC_SUPPORT_JIT ? function (self, klass) {
+ var TYPE = Attr.DELIMETER + 'type';
+ var EDITOR_ONLY = Attr.DELIMETER + 'editorOnly';
+ var DEFAULT = Attr.DELIMETER + 'default';
+ var FORMERLY_SERIALIZED_AS = Attr.DELIMETER + 'formerlySerializedAs';
+ var attrs = Attr.getClassAttrs(klass);
+
+ var props = klass.__values__;
+ // self, obj, serializedData, klass
+ var sources = [
+ 'var prop;'
+ ];
+ var fastMode = misc.BUILTIN_CLASSID_RE.test(js._getClassId(klass));
+ // sources.push('var vb,vn,vs,vo,vu,vf;'); // boolean, number, string, object, undefined, function
+ for (var p = 0; p < props.length; p++) {
+ var propName = props[p];
+ if ((CC_PREVIEW || (CC_EDITOR && self._ignoreEditorOnly)) && attrs[propName + EDITOR_ONLY]) {
+ continue; // skip editor only if in preview
+ }
+
+ var accessorToSet, propNameLiteralToSet;
+ if (CCClass.IDENTIFIER_RE.test(propName)) {
+ propNameLiteralToSet = '"' + propName + '"';
+ accessorToSet = '.' + propName;
+ }
+ else {
+ propNameLiteralToSet = CCClass.escapeForJS(propName);
+ accessorToSet = '[' + propNameLiteralToSet + ']';
+ }
+
+ var accessorToGet = accessorToSet;
+ if (attrs[propName + FORMERLY_SERIALIZED_AS]) {
+ var propNameToRead = attrs[propName + FORMERLY_SERIALIZED_AS];
+ if (CCClass.IDENTIFIER_RE.test(propNameToRead)) {
+ accessorToGet = '.' + propNameToRead;
+ }
+ else {
+ accessorToGet = '[' + CCClass.escapeForJS(propNameToRead) + ']';
+ }
+ }
+
+ sources.push('prop=d' + accessorToGet + ';');
+ sources.push(`if(typeof ${CC_JSB || CC_RUNTIME ? '(prop)' : 'prop'}!=="undefined"){`);
+
+ // function undefined object(null) string boolean number
+ var defaultValue = CCClass.getDefault(attrs[propName + DEFAULT]);
+ if (fastMode) {
+ var isPrimitiveType;
+ var userType = attrs[propName + TYPE];
+ if (defaultValue === undefined && userType) {
+ isPrimitiveType = userType instanceof Attr.PrimitiveType;
+ }
+ else {
+ var defaultType = typeof defaultValue;
+ isPrimitiveType = defaultType === 'string' ||
+ defaultType === 'number' ||
+ defaultType === 'boolean';
+ }
+
+ if (isPrimitiveType) {
+ sources.push(`o${accessorToSet}=prop;`);
+ }
+ else {
+ compileObjectTypeJit(sources, defaultValue, accessorToSet, propNameLiteralToSet, true);
+ }
+ }
+ else {
+ sources.push(`if(typeof ${CC_JSB || CC_RUNTIME ? '(prop)' : 'prop'}!=="object"){` +
+ 'o' + accessorToSet + '=prop;' +
+ '}else{');
+ compileObjectTypeJit(sources, defaultValue, accessorToSet, propNameLiteralToSet, false);
+ sources.push('}');
+ }
+ sources.push('}');
+ }
+ if (cc.js.isChildClassOf(klass, cc._BaseNode) || cc.js.isChildClassOf(klass, cc.Component)) {
+ if (CC_PREVIEW || (CC_EDITOR && self._ignoreEditorOnly)) {
+ var mayUsedInPersistRoot = js.isChildClassOf(klass, cc.Node);
+ if (mayUsedInPersistRoot) {
+ sources.push('d._id&&(o._id=d._id);');
+ }
+ }
+ else {
+ sources.push('d._id&&(o._id=d._id);');
+ }
+ }
+ if (props[props.length - 1] === '_$erialized') {
+ // deep copy original serialized data
+ sources.push('o._$erialized=JSON.parse(JSON.stringify(d));');
+ // parse the serialized data as primitive javascript object, so its __id__ will be dereferenced
+ sources.push('s._deserializePrimitiveObject(o._$erialized,d);');
+ }
+ return Function('s', 'o', 'd', 'k', sources.join(''));
+ } : function (self, klass) {
+ var fastMode = misc.BUILTIN_CLASSID_RE.test(js._getClassId(klass));
+ var shouldCopyId = cc.js.isChildClassOf(klass, cc._BaseNode) || cc.js.isChildClassOf(klass, cc.Component);
+ var shouldCopyRawData;
+
+ var simpleProps = [];
+ var simplePropsToRead = simpleProps;
+ var advancedProps = [];
+ var advancedPropsToRead = advancedProps;
+ var advancedPropsValueType = [];
+
+ (function () {
+ var props = klass.__values__;
+ shouldCopyRawData = props[props.length - 1] === '_$erialized';
+
+ var attrs = Attr.getClassAttrs(klass);
+ var TYPE = Attr.DELIMETER + 'type';
+ var DEFAULT = Attr.DELIMETER + 'default';
+ var FORMERLY_SERIALIZED_AS = Attr.DELIMETER + 'formerlySerializedAs';
+
+ for (var p = 0; p < props.length; p++) {
+ var propName = props[p];
+ var propNameToRead = propName;
+ if (attrs[propName + FORMERLY_SERIALIZED_AS]) {
+ propNameToRead = attrs[propName + FORMERLY_SERIALIZED_AS];
+ }
+ // function undefined object(null) string boolean number
+ var defaultValue = CCClass.getDefault(attrs[propName + DEFAULT]);
+ var isPrimitiveType = false;
+ if (fastMode) {
+ var userType = attrs[propName + TYPE];
+ if (defaultValue === undefined && userType) {
+ isPrimitiveType = userType instanceof Attr.PrimitiveType;
+ }
+ else {
+ var defaultType = typeof defaultValue;
+ isPrimitiveType = defaultType === 'string' ||
+ defaultType === 'number' ||
+ defaultType === 'boolean';
+ }
+ }
+ if (fastMode && isPrimitiveType) {
+ if (propNameToRead !== propName && simplePropsToRead === simpleProps) {
+ simplePropsToRead = simpleProps.slice();
+ }
+ simpleProps.push(propName);
+ if (simplePropsToRead !== simpleProps) {
+ simplePropsToRead.push(propNameToRead);
+ }
+ }
+ else {
+ if (propNameToRead !== propName && advancedPropsToRead === advancedProps) {
+ advancedPropsToRead = advancedProps.slice();
+ }
+ advancedProps.push(propName);
+ if (advancedPropsToRead !== advancedProps) {
+ advancedPropsToRead.push(propNameToRead);
+ }
+ advancedPropsValueType.push((defaultValue instanceof cc.ValueType) && defaultValue.constructor);
+ }
+ }
+ })();
+
+ return function (s, o, d, k) {
+ for (let i = 0; i < simpleProps.length; ++i) {
+ let prop = d[simplePropsToRead[i]];
+ if (prop !== undefined) {
+ o[simpleProps[i]] = prop;
+ }
+ }
+ for (let i = 0; i < advancedProps.length; ++i) {
+ let propName = advancedProps[i];
+ var prop = d[advancedPropsToRead[i]];
+ if (prop === undefined) {
+ continue;
+ }
+ if (!fastMode && typeof prop !== 'object') {
+ o[propName] = prop;
+ }
+ else {
+ // fastMode (so will not simpleProp) or object
+ var valueTypeCtor = advancedPropsValueType[i];
+ if (valueTypeCtor) {
+ if (fastMode || prop) {
+ s._deserializeTypedObject(o[propName], prop, valueTypeCtor);
+ }
+ else {
+ o[propName] = null;
+ }
+ }
+ else {
+ if (prop) {
+ s._deserializeObjField(o, prop, propName);
+ }
+ else {
+ o[propName] = null;
+ }
+ }
+ }
+ }
+ if (shouldCopyId && d._id) {
+ o._id = d._id;
+ }
+ if (shouldCopyRawData) {
+ // deep copy original serialized data
+ o._$erialized = JSON.parse(JSON.stringify(d));
+ // parse the serialized data as primitive javascript object, so its __id__ will be dereferenced
+ s._deserializePrimitiveObject(o._$erialized, d);
+ }
+ }
+ };
+
+ function unlinkUnusedPrefab (self, serialized, obj) {
+ var uuid = serialized['asset'] && serialized['asset'].__uuid__;
+ if (uuid) {
+ var last = self.result.uuidList.length - 1;
+ if (self.result.uuidList[last] === uuid &&
+ self.result.uuidObjList[last] === obj &&
+ self.result.uuidPropList[last] === 'asset') {
+ self.result.uuidList.pop();
+ self.result.uuidObjList.pop();
+ self.result.uuidPropList.pop();
+ }
+ else {
+ var debugEnvOnlyInfo = 'Failed to skip prefab asset while deserializing PrefabInfo';
+ cc.warn(debugEnvOnlyInfo);
+ }
+ }
+ }
+
+ function _deserializeFireClass (self, obj, serialized, klass) {
+ var deserialize;
+ if (klass.hasOwnProperty('__deserialize__')) {
+ deserialize = klass.__deserialize__;
+ }
+ else {
+ deserialize = compileDeserialize(self, klass);
+ // if (CC_TEST && !isPhantomJS) {
+ // cc.log(deserialize);
+ // }
+ js.value(klass, '__deserialize__', deserialize, true);
+ }
+ deserialize(self, obj, serialized, klass);
+ // if preview or build worker
+ if (CC_PREVIEW || (CC_EDITOR && self._ignoreEditorOnly)) {
+ if (klass === cc._PrefabInfo && !obj.sync) {
+ unlinkUnusedPrefab(self, serialized, obj);
+ }
+ }
+ }
+
+ _Deserializer.pool = new js.Pool(function (obj) {
+ obj.result = null;
+ obj.customEnv = null;
+ obj.deserializedList.length = 0;
+ obj.deserializedData = null;
+ obj._classFinder = null;
+ obj._idList.length = 0;
+ obj._idObjList.length = 0;
+ obj._idPropList.length = 0;
+ }, 1);
+
+ _Deserializer.pool.get = function (result, classFinder, customEnv, ignoreEditorOnly) {
+ var cache = this._get();
+ if (cache) {
+ cache.result = result;
+ cache.customEnv = customEnv;
+ cache._classFinder = classFinder;
+ if (!CC_BUILD) {
+ cache._ignoreEditorOnly = ignoreEditorOnly;
+ }
+ return cache;
+ }
+ else {
+ return new _Deserializer(result, classFinder, customEnv, ignoreEditorOnly);
+ }
+ };
+
+ return _Deserializer;
+})();
+
+/**
+ * @module cc
+ */
+
+/**
+ * !#en Deserialize json to cc.Asset
+ * !#zh 将 JSON 反序列化为对象实例。
+ *
+ * @method deserialize
+ * @param {String|Object} data - the serialized cc.Asset json string or json object.
+ * @param {Details} [details] - additional loading result
+ * @param {Object} [options]
+ * @return {object} the main data(asset)
+ */
+let deserialize = module.exports = function (data, details, options) {
+ options = options || {};
+ var classFinder = options.classFinder || js._getClassById;
+ // 启用 createAssetRefs 后,如果有 url 属性则会被统一强制设置为 { uuid: 'xxx' },必须后面再特殊处理
+ var createAssetRefs = options.createAssetRefs || cc.sys.platform === cc.sys.EDITOR_CORE;
+ var customEnv = options.customEnv;
+ var ignoreEditorOnly = options.ignoreEditorOnly;
+
+ //var oldJson = JSON.stringify(data, null, 2);
+
+ var tempDetails = !details;
+ details = details || Details.pool.get();
+ var deserializer = _Deserializer.pool.get(details, classFinder, customEnv, ignoreEditorOnly);
+
+ cc.game._isCloning = true;
+ var res = deserializer.deserialize(data);
+ cc.game._isCloning = false;
+
+ _Deserializer.pool.put(deserializer);
+ if (createAssetRefs) {
+ details.assignAssetsBy(Editor.serialize.asAsset);
+ }
+ if (tempDetails) {
+ Details.pool.put(details);
+ }
+
+ //var afterJson = JSON.stringify(data, null, 2);
+ //if (oldJson !== afterJson) {
+ // throw new Error('JSON SHOULD not changed');
+ //}
+
+ return res;
+};
+
+deserialize.Details = Details;
diff --git a/cocos2d/core/platform/deserialize.js b/cocos2d/core/platform/deserialize.js
index 1223b531cb4..3533ffe0cdb 100644
--- a/cocos2d/core/platform/deserialize.js
+++ b/cocos2d/core/platform/deserialize.js
@@ -1,8 +1,8 @@
/****************************************************************************
Copyright (c) 2013-2016 Chukong Technologies Inc.
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+ Copyright (c) 2017-2020 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -24,799 +24,39 @@
THE SOFTWARE.
****************************************************************************/
-var js = require('./js');
-var Attr = require('./attribute');
-var CCClass = require('./CCClass');
-var misc = require('../utils/misc');
+import deserializeForCompiled from './deserialize-compiled';
-// HELPERS
-
-/**
- * !#en Contains information collected during deserialization
- * !#zh 包含反序列化时的一些信息
- * @class Details
- *
- */
-var Details = function () {
- /**
- * list of the depends assets' uuid
- * @property {String[]} uuidList
- */
- this.uuidList = [];
- /**
- * the obj list whose field needs to load asset by uuid
- * @property {Object[]} uuidObjList
- */
- this.uuidObjList = [];
- /**
- * the corresponding field name which referenced to the asset
- * @property {String[]} uuidPropList
- */
- this.uuidPropList = [];
-
- // TODO - DELME since 2.0
- this._stillUseUrl = js.createMap(true);
-};
-/**
- * @method reset
- */
-Details.prototype.reset = function () {
- this.uuidList.length = 0;
- this.uuidObjList.length = 0;
- this.uuidPropList.length = 0;
- js.clear(this._stillUseUrl);
-};
-if (CC_EDITOR || CC_TEST) {
- Details.prototype.assignAssetsBy = function (getter) {
- // ignore this._stillUseUrl
- for (var i = 0, len = this.uuidList.length; i < len; i++) {
- var uuid = this.uuidList[i];
- var obj = this.uuidObjList[i];
- var prop = this.uuidPropList[i];
- obj[prop] = getter(uuid);
- }
- };
-}
-// /**
-// * @method getUuidOf
-// * @param {Object} obj
-// * @param {String} propName
-// * @return {String}
-// */
-// Details.prototype.getUuidOf = function (obj, propName) {
-// for (var i = 0; i < this.uuidObjList.length; i++) {
-// if (this.uuidObjList[i] === obj && this.uuidPropList[i] === propName) {
-// return this.uuidList[i];
-// }
-// }
-// return "";
-// };
-/**
- * @method push
- * @param {Object} obj
- * @param {String} propName
- * @param {String} uuid
- */
-Details.prototype.push = function (obj, propName, uuid, _stillUseUrl) {
- if (_stillUseUrl) {
- this._stillUseUrl[this.uuidList.length] = true;
- }
- this.uuidList.push(uuid);
- this.uuidObjList.push(obj);
- this.uuidPropList.push(propName);
-};
-
-Details.pool = new js.Pool(function (obj) {
- obj.reset();
-}, 10);
-
-Details.pool.get = function () {
- return this._get() || new Details();
-};
-
-// IMPLEMENT OF DESERIALIZATION
-
-var _Deserializer = (function () {
- function _Deserializer(result, target, classFinder, customEnv, ignoreEditorOnly) {
- this.result = result;
- this.customEnv = customEnv;
- this.deserializedList = [];
- this.deserializedData = null;
- this._classFinder = classFinder;
- if (CC_DEV) {
- this._target = target;
- this._ignoreEditorOnly = ignoreEditorOnly;
- }
- this._idList = [];
- this._idObjList = [];
- this._idPropList = [];
- }
-
- function _dereference (self) {
- // 这里不采用遍历反序列化结果的方式,因为反序列化的结果如果引用到复杂的外部库,很容易堆栈溢出。
- var deserializedList = self.deserializedList;
- var idPropList = self._idPropList;
- var idList = self._idList;
- var idObjList = self._idObjList;
- var onDereferenced = self._classFinder && self._classFinder.onDereferenced;
- var i, propName, id;
- if (CC_EDITOR && onDereferenced) {
- for (i = 0; i < idList.length; i++) {
- propName = idPropList[i];
- id = idList[i];
- idObjList[i][propName] = deserializedList[id];
- onDereferenced(deserializedList, id, idObjList[i], propName);
- }
- }
- else {
- for (i = 0; i < idList.length; i++) {
- propName = idPropList[i];
- id = idList[i];
- idObjList[i][propName] = deserializedList[id];
- }
- }
+deserializeForCompiled.reportMissingClass = function (id) {
+ if (CC_EDITOR && Editor.Utils.UuidUtils.isUuid(id)) {
+ id = Editor.Utils.UuidUtils.decompressUuid(id);
+ cc.warnID(5301, id);
}
-
- var prototype = _Deserializer.prototype;
-
- prototype.deserialize = function (jsonObj) {
- if (Array.isArray(jsonObj)) {
- var jsonArray = jsonObj;
- var refCount = jsonArray.length;
- this.deserializedList.length = refCount;
- // deserialize
- for (var i = 0; i < refCount; i++) {
- if (jsonArray[i]) {
- if (CC_EDITOR || CC_TEST) {
- var mainTarget = (i === 0 && this._target);
- this.deserializedList[i] = this._deserializeObject(jsonArray[i], false, mainTarget, this.deserializedList, '' + i);
- }
- else {
- this.deserializedList[i] = this._deserializeObject(jsonArray[i], false);
- }
- }
- }
- this.deserializedData = refCount > 0 ? this.deserializedList[0] : [];
-
- //// callback
- //for (var j = 0; j < refCount; j++) {
- // if (referencedList[j].onAfterDeserialize) {
- // referencedList[j].onAfterDeserialize();
- // }
- //}
- }
- else {
- this.deserializedList.length = 1;
- if (CC_EDITOR || CC_TEST) {
- this.deserializedData = jsonObj ? this._deserializeObject(jsonObj, false, this._target, this.deserializedList, '0') : null;
- }
- else {
- this.deserializedData = jsonObj ? this._deserializeObject(jsonObj, false) : null;
- }
- this.deserializedList[0] = this.deserializedData;
-
- //// callback
- //if (deserializedData.onAfterDeserialize) {
- // deserializedData.onAfterDeserialize();
- //}
- }
-
- // dereference
- _dereference(this);
-
- return this.deserializedData;
- };
-
- ///**
- // * @param {Object} serialized - The obj to deserialize, must be non-nil
- // * @param {Boolean} _stillUseUrl
- // * @param {Object} [target=null] - editor only
- // * @param {Object} [owner] - debug only
- // * @param {String} [propName] - debug only
- // */
- prototype._deserializeObject = function (serialized, _stillUseUrl, target, owner, propName) {
- var prop;
- var obj = null; // the obj to return
- var klass = null;
- var type = serialized.__type__;
- if (type) {
-
- // Type Object (including CCClass)
-
- klass = this._classFinder(type, serialized, owner, propName);
- if (!klass) {
- var notReported = this._classFinder === js._getClassById;
- if (notReported) {
- cc.deserialize.reportMissingClass(type);
- }
- return null;
- }
-
- if ((CC_EDITOR || CC_TEST) && target) {
- // use target
- if ( !(target instanceof klass) ) {
- cc.warnID(5300, js.getClassName(target), klass);
- }
- obj = target;
- }
- else {
- // instantiate a new object
- obj = new klass();
- }
-
- if (obj._deserialize) {
- obj._deserialize(serialized.content, this);
- return obj;
- }
- if (cc.Class._isCCClass(klass)) {
- _deserializeFireClass(this, obj, serialized, klass, target);
- }
- else {
- this._deserializeTypedObject(obj, serialized, klass);
- }
- }
- else if ( !Array.isArray(serialized) ) {
-
- // embedded primitive javascript object
-
- obj = ((CC_EDITOR || CC_TEST) && target) || {};
- this._deserializePrimitiveObject(obj, serialized);
- }
- else {
-
- // Array
-
- if ((CC_EDITOR || CC_TEST) && target) {
- target.length = serialized.length;
- obj = target;
- }
- else {
- obj = new Array(serialized.length);
- }
-
- for (var i = 0; i < serialized.length; i++) {
- prop = serialized[i];
- if (typeof prop === 'object' && prop) {
- if (CC_EDITOR || CC_TEST) {
- this._deserializeObjField(obj, prop, '' + i, target && obj, _stillUseUrl);
- }
- else {
- this._deserializeObjField(obj, prop, '' + i, null, _stillUseUrl);
- }
- }
- else {
- obj[i] = prop;
- }
- }
- }
- return obj;
- };
-
- // 和 _deserializeObject 不同的地方在于会判断 id 和 uuid
- prototype._deserializeObjField = function (obj, jsonObj, propName, target, _stillUseUrl) {
- var id = jsonObj.__id__;
- if (id === undefined) {
- var uuid = jsonObj.__uuid__;
- if (uuid) {
- //if (ENABLE_TARGET) {
- //这里不做任何操作,因为有可能调用者需要知道依赖哪些 asset。
- //调用者使用 uuidList 时,可以判断 obj[propName] 是否为空,为空则表示待进一步加载,
- //不为空则只是表明依赖关系。
- // if (target && target[propName] && target[propName]._uuid === uuid) {
- // console.assert(obj[propName] === target[propName]);
- // return;
- // }
- // }
- this.result.push(obj, propName, uuid, _stillUseUrl);
- }
- else {
- if (CC_EDITOR || CC_TEST) {
- obj[propName] = this._deserializeObject(jsonObj, _stillUseUrl, target && target[propName], obj, propName);
- }
- else {
- obj[propName] = this._deserializeObject(jsonObj, _stillUseUrl);
- }
- }
- }
- else {
- var dObj = this.deserializedList[id];
- if (dObj) {
- obj[propName] = dObj;
- }
- else {
- this._idList.push(id);
- this._idObjList.push(obj);
- this._idPropList.push(propName);
- }
- }
- };
-
- prototype._deserializePrimitiveObject = function (instance, serialized) {
- var self = this;
- for (var propName in serialized) {
- if (serialized.hasOwnProperty(propName)) {
- var prop = serialized[propName];
- if (typeof prop !== 'object') {
- if (propName !== '__type__'/* && k != '__id__'*/) {
- instance[propName] = prop;
- }
- }
- else {
- if (prop) {
- if (CC_EDITOR || CC_TEST) {
- self._deserializeObjField(instance, prop, propName, self._target && instance);
- }
- else {
- self._deserializeObjField(instance, prop, propName);
- }
- }
- else {
- instance[propName] = null;
- }
- }
-
- }
- }
- };
-
- // function _compileTypedObject (accessor, klass, ctorCode) {
- // if (klass === cc.Vec2) {
- // return `{` +
- // `o${accessor}.x=prop.x||0;` +
- // `o${accessor}.y=prop.y||0;` +
- // `}`;
- // }
- // else if (klass === cc.Color) {
- // return `{` +
- // `o${accessor}.r=prop.r||0;` +
- // `o${accessor}.g=prop.g||0;` +
- // `o${accessor}.b=prop.b||0;` +
- // `o${accessor}.a=(prop.a===undefined?255:prop.a);` +
- // `}`;
- // }
- // else if (klass === cc.Size) {
- // return `{` +
- // `o${accessor}.width=prop.width||0;` +
- // `o${accessor}.height=prop.height||0;` +
- // `}`;
- // }
- // else {
- // return `s._deserializeTypedObject(o${accessor},prop,${ctorCode});`;
- // }
- // }
-
- prototype._deserializeTypedObject = function (instance, serialized, klass) {
- if (klass === cc.Vec2) {
- instance.x = serialized.x || 0;
- instance.y = serialized.y || 0;
- return;
- }
- else if (klass === cc.Color) {
- instance.r = serialized.r || 0;
- instance.g = serialized.g || 0;
- instance.b = serialized.b || 0;
- var a = serialized.a;
- instance.a = (a === undefined ? 255 : a);
- return;
- }
- else if (klass === cc.Size) {
- instance.width = serialized.width || 0;
- instance.height = serialized.height || 0;
- return;
- }
-
- var fastDefinedProps = klass.__props__;
- if (!fastDefinedProps) {
- fastDefinedProps = Object.keys(instance); // 遍历 instance,如果具有类型,才不会把 __type__ 也读进来
- }
- for (var i = 0; i < fastDefinedProps.length; i++) {
- var propName = fastDefinedProps[i];
- var prop = serialized[propName];
- if (prop !== undefined && serialized.hasOwnProperty(propName)) {
- if (typeof prop !== 'object') {
- instance[propName] = prop;
- }
- else if (prop) {
- if (CC_EDITOR || CC_TEST) {
- this._deserializeObjField(instance, prop, propName, this._target && instance);
- }
- else {
- this._deserializeObjField(instance, prop, propName);
- }
- }
- else {
- instance[propName] = null;
- }
- }
- }
- };
-
- function compileObjectTypeJit (sources, defaultValue, accessorToSet, propNameLiteralToSet, assumeHavePropIfIsValue, stillUseUrl) {
- if (defaultValue instanceof cc.ValueType) {
- // fast case
- if (!assumeHavePropIfIsValue) {
- sources.push('if(prop){');
- }
- var ctorCode = js.getClassName(defaultValue);
- sources.push(`s._deserializeTypedObject(o${accessorToSet},prop,${ctorCode});`);
- if (!assumeHavePropIfIsValue) {
- sources.push('}else o' + accessorToSet + '=null;');
- }
- }
- else {
- sources.push('if(prop){');
- sources.push('s._deserializeObjField(o,prop,' +
- propNameLiteralToSet +
- ((CC_EDITOR || CC_TEST) ? ',t&&o,' : ',null,') +
- !!stillUseUrl +
- ');');
- sources.push('}else o' + accessorToSet + '=null;');
- }
+ else {
+ cc.warnID(5302, id);
}
+};
- var compileDeserialize = CC_SUPPORT_JIT ? function (self, klass) {
- var TYPE = Attr.DELIMETER + 'type';
- var EDITOR_ONLY = Attr.DELIMETER + 'editorOnly';
- var DEFAULT = Attr.DELIMETER + 'default';
- var SAVE_URL_AS_ASSET = Attr.DELIMETER + 'saveUrlAsAsset';
- var FORMERLY_SERIALIZED_AS = Attr.DELIMETER + 'formerlySerializedAs';
- var attrs = Attr.getClassAttrs(klass);
-
- var props = klass.__values__;
- // self, obj, serializedData, klass, target
- var sources = [
- 'var prop;'
- ];
- var fastMode = misc.BUILTIN_CLASSID_RE.test(js._getClassId(klass));
- // sources.push('var vb,vn,vs,vo,vu,vf;'); // boolean, number, string, object, undefined, function
- for (var p = 0; p < props.length; p++) {
- var propName = props[p];
- if ((CC_PREVIEW || (CC_EDITOR && self._ignoreEditorOnly)) && attrs[propName + EDITOR_ONLY]) {
- continue; // skip editor only if in preview
- }
-
- var accessorToSet, propNameLiteralToSet;
- if (CCClass.IDENTIFIER_RE.test(propName)) {
- propNameLiteralToSet = '"' + propName + '"';
- accessorToSet = '.' + propName;
- }
- else {
- propNameLiteralToSet = CCClass.escapeForJS(propName);
- accessorToSet = '[' + propNameLiteralToSet + ']';
- }
-
- var accessorToGet = accessorToSet;
- if (attrs[propName + FORMERLY_SERIALIZED_AS]) {
- var propNameToRead = attrs[propName + FORMERLY_SERIALIZED_AS];
- if (CCClass.IDENTIFIER_RE.test(propNameToRead)) {
- accessorToGet = '.' + propNameToRead;
- }
- else {
- accessorToGet = '[' + CCClass.escapeForJS(propNameToRead) + ']';
- }
- }
-
- sources.push('prop=d' + accessorToGet + ';');
- sources.push(`if(typeof ${CC_JSB ? '(prop)' : 'prop'}!=="undefined"){`);
-
- var stillUseUrl = attrs[propName + SAVE_URL_AS_ASSET];
- // function undefined object(null) string boolean number
- var defaultValue = CCClass.getDefault(attrs[propName + DEFAULT]);
- if (fastMode) {
- var isPrimitiveType;
- var userType = attrs[propName + TYPE];
- if (defaultValue === undefined && userType) {
- isPrimitiveType = userType === cc.String ||
- userType === cc.Integer ||
- userType === cc.Float ||
- userType === cc.Boolean;
- }
- else {
- var defaultType = typeof defaultValue;
- isPrimitiveType = (defaultType === 'string' && !stillUseUrl) ||
- defaultType === 'number' ||
- defaultType === 'boolean';
- }
-
- if (isPrimitiveType) {
- sources.push(`o${accessorToSet}=prop;`);
- }
- else {
- compileObjectTypeJit(sources, defaultValue, accessorToSet, propNameLiteralToSet, true, stillUseUrl);
- }
- }
- else {
- sources.push(`if(typeof ${CC_JSB ? '(prop)' : 'prop'}!=="object"){` +
- 'o' + accessorToSet + '=prop;' +
- '}else{');
- compileObjectTypeJit(sources, defaultValue, accessorToSet, propNameLiteralToSet, false, stillUseUrl);
- sources.push('}');
- }
- sources.push('}');
- }
- if (cc.js.isChildClassOf(klass, cc._BaseNode) || cc.js.isChildClassOf(klass, cc.Component)) {
- if (CC_PREVIEW || (CC_EDITOR && self._ignoreEditorOnly)) {
- var mayUsedInPersistRoot = js.isChildClassOf(klass, cc.Node);
- if (mayUsedInPersistRoot) {
- sources.push('d._id&&(o._id=d._id);');
- }
- }
- else {
- sources.push('d._id&&(o._id=d._id);');
- }
- }
- if (props[props.length - 1] === '_$erialized') {
- // deep copy original serialized data
- sources.push('o._$erialized=JSON.parse(JSON.stringify(d));');
- // parse the serialized data as primitive javascript object, so its __id__ will be dereferenced
- sources.push('s._deserializePrimitiveObject(o._$erialized,d);');
- }
- return Function('s', 'o', 'd', 'k', 't', sources.join(''));
- } : function (self, klass) {
- var fastMode = misc.BUILTIN_CLASSID_RE.test(js._getClassId(klass));
- var shouldCopyId = cc.js.isChildClassOf(klass, cc._BaseNode) || cc.js.isChildClassOf(klass, cc.Component);
- var shouldCopyRawData;
-
- var simpleProps = [];
- var simplePropsToRead = simpleProps;
- var advancedProps = [];
- var advancedPropsToRead = advancedProps;
- var advancedPropsUseUrl = [];
- var advancedPropsValueType = [];
-
- (function () {
- var props = klass.__values__;
- shouldCopyRawData = props[props.length - 1] === '_$erialized';
-
- var attrs = Attr.getClassAttrs(klass);
- var TYPE = Attr.DELIMETER + 'type';
- var DEFAULT = Attr.DELIMETER + 'default';
- var SAVE_URL_AS_ASSET = Attr.DELIMETER + 'saveUrlAsAsset';
- var FORMERLY_SERIALIZED_AS = Attr.DELIMETER + 'formerlySerializedAs';
-
- for (var p = 0; p < props.length; p++) {
- var propName = props[p];
- var propNameToRead = propName;
- if (attrs[propName + FORMERLY_SERIALIZED_AS]) {
- propNameToRead = attrs[propName + FORMERLY_SERIALIZED_AS];
- }
- var stillUseUrl = attrs[propName + SAVE_URL_AS_ASSET];
- // function undefined object(null) string boolean number
- var defaultValue = CCClass.getDefault(attrs[propName + DEFAULT]);
- var isPrimitiveType = false;
- if (fastMode) {
- var userType = attrs[propName + TYPE];
- if (defaultValue === undefined && userType) {
- isPrimitiveType = userType === cc.String ||
- userType === cc.Integer ||
- userType === cc.Float ||
- userType === cc.Boolean;
- }
- else {
- var defaultType = typeof defaultValue;
- isPrimitiveType = (defaultType === 'string' && !stillUseUrl) ||
- defaultType === 'number' ||
- defaultType === 'boolean';
- }
- }
- if (fastMode && isPrimitiveType) {
- if (propNameToRead !== propName && simplePropsToRead === simpleProps) {
- simplePropsToRead = simpleProps.slice();
- }
- simpleProps.push(propName);
- if (simplePropsToRead !== simpleProps) {
- simplePropsToRead.push(propNameToRead);
- }
- }
- else {
- if (propNameToRead !== propName && advancedPropsToRead === advancedProps) {
- advancedPropsToRead = advancedProps.slice();
- }
- advancedProps.push(propName);
- if (advancedPropsToRead !== advancedProps) {
- advancedPropsToRead.push(propNameToRead);
- }
- advancedPropsUseUrl.push(stillUseUrl);
- advancedPropsValueType.push((defaultValue instanceof cc.ValueType) && defaultValue.constructor);
- }
- }
- })();
-
- return function (s, o, d, k, t) {
- for (let i = 0; i < simpleProps.length; ++i) {
- let prop = d[simplePropsToRead[i]];
- if (prop !== undefined) {
- o[simpleProps[i]] = prop;
- }
- }
- for (let i = 0; i < advancedProps.length; ++i) {
- let propName = advancedProps[i];
- var prop = d[advancedPropsToRead[i]];
- if (prop === undefined) {
- continue;
- }
- if (!fastMode && typeof prop !== 'object') {
- o[propName] = prop;
- }
- else {
- // fastMode (so will not simpleProp) or object
- var valueTypeCtor = advancedPropsValueType[i];
- if (valueTypeCtor) {
- if (fastMode || prop) {
- s._deserializeTypedObject(o[propName], prop, valueTypeCtor);
- }
- else {
- o[propName] = null;
- }
- }
- else {
- if (prop) {
- s._deserializeObjField(
- o,
- prop,
- propName,
- (CC_EDITOR || CC_TEST) ? (t && o) : null,
- advancedPropsUseUrl[i],
- );
- }
- else {
- o[propName] = null;
- }
- }
- }
- }
- if (shouldCopyId && d._id) {
- o._id = d._id;
- }
- if (shouldCopyRawData) {
- // deep copy original serialized data
- o._$erialized = JSON.parse(JSON.stringify(d));
- // parse the serialized data as primitive javascript object, so its __id__ will be dereferenced
- s._deserializePrimitiveObject(o._$erialized, d);
- }
- }
- };
-
- function unlinkUnusedPrefab (self, serialized, obj) {
- var uuid = serialized['asset'] && serialized['asset'].__uuid__;
- if (uuid) {
- var last = self.result.uuidList.length - 1;
- if (self.result.uuidList[last] === uuid &&
- self.result.uuidObjList[last] === obj &&
- self.result.uuidPropList[last] === 'asset') {
- self.result.uuidList.pop();
- self.result.uuidObjList.pop();
- self.result.uuidPropList.pop();
- }
- else {
- var debugEnvOnlyInfo = 'Failed to skip prefab asset while deserializing PrefabInfo';
- cc.warn(debugEnvOnlyInfo);
- }
- }
- }
+if (CC_BUILD) {
+ cc.deserialize = deserializeForCompiled;
+}
+else {
+ let deserializeForEditor = require('./deserialize-editor');
- function _deserializeFireClass (self, obj, serialized, klass, target) {
- var deserialize;
- if (klass.hasOwnProperty('__deserialize__')) {
- deserialize = klass.__deserialize__;
- }
- else {
- deserialize = compileDeserialize(self, klass);
- // if (CC_TEST && !isPhantomJS) {
- // cc.log(deserialize);
- // }
- js.value(klass, '__deserialize__', deserialize, true);
- }
- deserialize(self, obj, serialized, klass, target);
- // if preview or build worker
- if (CC_PREVIEW || (CC_EDITOR && self._ignoreEditorOnly)) {
- if (klass === cc._PrefabInfo && !obj.sync) {
- unlinkUnusedPrefab(self, serialized, obj);
- }
+ cc.deserialize = function (data, details, options) {
+ if (CC_EDITOR && Buffer.isBuffer(data)) {
+ data = data.toString();
}
- }
-
- _Deserializer.pool = new js.Pool(function (obj) {
- obj.result = null;
- obj.customEnv = null;
- obj.deserializedList.length = 0;
- obj.deserializedData = null;
- obj._classFinder = null;
- if (CC_DEV) {
- obj._target = null;
+ if (typeof data === 'string') {
+ data = JSON.parse(data);
}
- obj._idList.length = 0;
- obj._idObjList.length = 0;
- obj._idPropList.length = 0;
- }, 1);
-
- _Deserializer.pool.get = function (result, target, classFinder, customEnv, ignoreEditorOnly) {
- var cache = this._get();
- if (cache) {
- cache.result = result;
- cache.customEnv = customEnv;
- cache._classFinder = classFinder;
- if (CC_DEV) {
- cache._target = target;
- cache._ignoreEditorOnly = ignoreEditorOnly;
+ if (CC_PREVIEW) {
+ // support for loading Asset Bundle from server
+ if (deserializeForCompiled.isCompiledJson(data)) {
+ return deserializeForCompiled(data, details, options);
}
- return cache;
- }
- else {
- return new _Deserializer(result, target, classFinder, customEnv, ignoreEditorOnly);
}
+ return deserializeForEditor(data, details, options);
};
-
- return _Deserializer;
-})();
-
-/**
- * @module cc
- */
-
-/**
- * !#en Deserialize json to cc.Asset
- * !#zh 将 JSON 反序列化为对象实例。
- *
- * 当指定了 target 选项时,如果 target 引用的其它 asset 的 uuid 不变,则不会改变 target 对 asset 的引用,
- * 也不会将 uuid 保存到 result 对象中。
- *
- * @method deserialize
- * @param {String|Object} data - the serialized cc.Asset json string or json object.
- * @param {Details} [details] - additional loading result
- * @param {Object} [options]
- * @return {object} the main data(asset)
- */
-cc.deserialize = function (data, details, options) {
- options = options || {};
- var classFinder = options.classFinder || js._getClassById;
- // 启用 createAssetRefs 后,如果有 url 属性则会被统一强制设置为 { uuid: 'xxx' },必须后面再特殊处理
- var createAssetRefs = options.createAssetRefs || cc.sys.platform === cc.sys.EDITOR_CORE;
- var target = (CC_EDITOR || CC_TEST) && options.target;
- var customEnv = options.customEnv;
- var ignoreEditorOnly = options.ignoreEditorOnly;
-
- if (CC_EDITOR && Buffer.isBuffer(data)) {
- data = data.toString();
- }
-
- if (typeof data === 'string') {
- data = JSON.parse(data);
- }
-
- //var oldJson = JSON.stringify(data, null, 2);
-
- var tempDetails = !details;
- details = details || Details.pool.get();
- var deserializer = _Deserializer.pool.get(details, target, classFinder, customEnv, ignoreEditorOnly);
-
- cc.game._isCloning = true;
- var res = deserializer.deserialize(data);
- cc.game._isCloning = false;
-
- _Deserializer.pool.put(deserializer);
- if (createAssetRefs) {
- details.assignAssetsBy(Editor.serialize.asAsset);
- }
- if (tempDetails) {
- Details.pool.put(details);
- }
-
- //var afterJson = JSON.stringify(data, null, 2);
- //if (oldJson !== afterJson) {
- // throw new Error('JSON SHOULD not changed');
- //}
-
- return res;
-};
-
-cc.deserialize.Details = Details;
-cc.deserialize.reportMissingClass = function (id) {
- if (CC_EDITOR && Editor.Utils.UuidUtils.isUuid(id)) {
- id = Editor.Utils.UuidUtils.decompressUuid(id);
- cc.warnID(5301, id);
- }
- else {
- cc.warnID(5302, id);
- }
-};
\ No newline at end of file
+ cc.deserialize.reportMissingClass = deserializeForCompiled.reportMissingClass;
+ cc.deserialize.Details = deserializeForEditor.Details;
+}
diff --git a/cocos2d/core/platform/id-generater.js b/cocos2d/core/platform/id-generater.js
index 4a7ae2f4994..c08a3c01f93 100644
--- a/cocos2d/core/platform/id-generater.js
+++ b/cocos2d/core/platform/id-generater.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/platform/index.js b/cocos2d/core/platform/index.js
index 7c9d7d93680..6ec8f956ee5 100644
--- a/cocos2d/core/platform/index.js
+++ b/cocos2d/core/platform/index.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -30,7 +30,6 @@ require('./CCClassDecorator');
require('./CCEnum');
require('./CCObject');
require('./callbacks-invoker');
-require('./url');
require('./deserialize');
require('./instantiate');
require('./instantiate-jit');
@@ -39,6 +38,5 @@ require('./CCSys');
require('./CCMacro');
if (!(CC_EDITOR && Editor.isMainProcess)) {
- require('./CCAssetLibrary');
require('./CCVisibleRect');
}
\ No newline at end of file
diff --git a/cocos2d/core/platform/instantiate-jit.js b/cocos2d/core/platform/instantiate-jit.js
index e4cf8baa927..22ab66e8b3d 100644
--- a/cocos2d/core/platform/instantiate-jit.js
+++ b/cocos2d/core/platform/instantiate-jit.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -55,6 +55,42 @@ const DEFAULT_MODULE_CACHE = {
'cc.PrefabInfo': false
};
+try {
+ // compatible for IE
+ !Float32Array.name && (Float32Array.name = 'Float32Array');
+ !Float64Array.name && (Float64Array.name = 'Float64Array');
+
+ !Int8Array.name && (Int8Array.name = 'Int8Array');
+ !Int16Array.name && (Int16Array.name = 'Int16Array');
+ !Int32Array.name && (Int32Array.name = 'Int32Array');
+
+ !Uint8Array.name && (Uint8Array.name = 'Uint8Array');
+ !Uint16Array.name && (Uint16Array.name = 'Uint16Array');
+ !Uint32Array.name && (Uint32Array.name = 'Uint32Array');
+
+ !Uint8ClampedArray.name && (Uint8ClampedArray.name = 'Uint8ClampedArray');
+}
+catch (e) {}
+
+// compatible for iOS 9
+function getTypedArrayName (constructor) {
+ if (constructor === Float32Array) { return 'Float32Array'; }
+ else if (constructor === Float64Array) { return 'Float64Array'; }
+
+ else if (constructor === Int8Array) { return 'Int8Array'; }
+ else if (constructor === Int16Array) { return 'Int16Array'; }
+ else if (constructor === Int32Array) { return 'Int32Array'; }
+
+ else if (constructor === Uint8Array) { return 'Uint8Array'; }
+ else if (constructor === Uint16Array) { return 'Uint16Array'; }
+ else if (constructor === Uint32Array) { return 'Uint32Array'; }
+
+ else if (constructor === Uint8ClampedArray) { return 'Uint8ClampedArray'; }
+ else {
+ throw new Error(`Unknown TypedArray to instantiate: ${constructor}`);
+ }
+}
+
// HELPER CLASSES
// ('foo', 'bar')
@@ -153,19 +189,21 @@ function equalsToDefault (def, value) {
if (def === value) {
return true;
}
- if (def && value) {
- if (def instanceof cc.ValueType && def.equals(value)) {
- return true;
- }
- if ((Array.isArray(def) && Array.isArray(value)) ||
- (def.constructor === Object && value.constructor === Object)
- ) {
- try {
- return Array.isArray(def) && Array.isArray(value) && def.length === 0 && value.length === 0;
- }
- catch (e) {
+ if (def && value &&
+ typeof def === 'object' && typeof value === 'object' &&
+ def.constructor === value.constructor)
+ {
+ if (def instanceof cc.ValueType) {
+ if (def.equals(value)) {
+ return true;
}
}
+ else if (Array.isArray(def)) {
+ return def.length === 0 && value.length === 0;
+ }
+ else if (def.constructor === Object) {
+ return js.isEmptyObject(def) && js.isEmptyObject(value);
+ }
}
return false;
}
@@ -220,7 +258,7 @@ function Parser (obj, parent) {
'}else{',
LOCAL_OBJ + '=R=new ' + this.getFuncModule(obj.constructor, true) + '();',
'}');
- obj._iN$t = { globalVar: 'R' };
+ js.value(obj, '_iN$t', { globalVar: 'R' }, true);
this.objsToClear_iN$t.push(obj);
this.enumerateObject(this.codeArray, obj);
//}
@@ -348,10 +386,10 @@ proto.instantiateArray = function (value) {
var codeArray = [declaration];
// assign a _iN$t flag to indicate that this object has been parsed.
- value._iN$t = {
+ js.value(value, '_iN$t', {
globalVar: '', // the name of declared global variable used to access this object
source: codeArray, // the source code array for this object
- };
+ }, true);
this.objsToClear_iN$t.push(value);
for (var i = 0; i < value.length; ++i) {
@@ -362,6 +400,32 @@ proto.instantiateArray = function (value) {
return codeArray;
};
+proto.instantiateTypedArray = function (value) {
+ let type = value.constructor.name || getTypedArrayName(value.constructor);
+ if (value.length === 0) {
+ return 'new ' + type;
+ }
+
+ let arrayVar = LOCAL_ARRAY + (++this.localVariableId);
+ let declaration = new Declaration(arrayVar, 'new ' + type + '(' + value.length + ')');
+ let codeArray = [declaration];
+
+ // assign a _iN$t flag to indicate that this object has been parsed.
+ value._iN$t = {
+ globalVar: '', // the name of declared global variable used to access this object
+ source: codeArray, // the source code array for this object
+ };
+ this.objsToClear_iN$t.push(value);
+
+ for (var i = 0; i < value.length; ++i) {
+ if (value[i] !== 0) {
+ var statement = arrayVar + '[' + i + ']=';
+ writeAssignment(codeArray, statement, value[i]);
+ }
+ }
+ return codeArray;
+};
+
proto.enumerateField = function (obj, key, value) {
if (typeof value === 'object' && value) {
var _iN$t = value._iN$t;
@@ -383,6 +447,9 @@ proto.enumerateField = function (obj, key, value) {
}
return globalVar;
}
+ else if (ArrayBuffer.isView(value)) {
+ return this.instantiateTypedArray(value);
+ }
else if (Array.isArray(value)) {
return this.instantiateArray(value);
}
@@ -487,12 +554,12 @@ proto.instantiateObj = function (obj) {
var codeArray = [createCode];
// assign a _iN$t flag to indicate that this object has been parsed.
- obj._iN$t = {
+ js.value(obj, '_iN$t', {
globalVar: '', // the name of declared global variable used to access this object
source: codeArray, // the source code array for this object
//propName: '', // the propName this object defined in its source code,
// // if defined, use LOCAL_OBJ.propName to access the obj, else just use o
- };
+ }, true);
this.objsToClear_iN$t.push(obj);
this.enumerateObject(codeArray, obj);
diff --git a/cocos2d/core/platform/instantiate.js b/cocos2d/core/platform/instantiate.js
index 61681c5fb58..6790a19a3e9 100644
--- a/cocos2d/core/platform/instantiate.js
+++ b/cocos2d/core/platform/instantiate.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -29,6 +29,7 @@ var CCValueType = require('../value-types/value-type');
var Destroyed = CCObject.Flags.Destroyed;
var PersistentMask = CCObject.Flags.PersistentMask;
var _isDomNode = require('./utils').isDomNode;
+var js = require('./js');
/**
* !#en Clones the object `original` and returns the clone, or instantiate a node from the Prefab.
@@ -87,7 +88,7 @@ function instantiate (original, internal_force) {
// @returns {Object} - the instantiated object
if (original._instantiate) {
cc.game._isCloning = true;
- clone = original._instantiate();
+ clone = original._instantiate(null, true);
cc.game._isCloning = false;
return clone;
}
@@ -183,7 +184,7 @@ function enumerateCCClass (klass, obj, clone, parent) {
function enumerateObject (obj, clone, parent) {
// 目前使用“_iN$t”这个特殊字段来存实例化后的对象,这样做主要是为了防止循环引用
// 注意,为了避免循环引用,所有新创建的实例,必须在赋值前被设为源对象的_iN$t
- obj._iN$t = clone;
+ js.value(obj, '_iN$t', clone, true);
objsToClearTmpVar.push(obj);
var klass = obj.constructor;
if (cc.Class._isCCClass(klass)) {
@@ -228,11 +229,22 @@ function instantiateObj (obj, parent) {
return obj;
}
var clone;
+ if (ArrayBuffer.isView(obj)) {
+ let len = obj.length;
+ clone = new (obj.constructor)(len);
+ obj._iN$t = clone;
+ objsToClearTmpVar.push(obj);
+ for (let i = 0; i < len; ++i) {
+ clone[i] = obj[i];
+ }
+ return clone;
+ }
if (Array.isArray(obj)) {
- var len = obj.length;
+ let len = obj.length;
clone = new Array(len);
- obj._iN$t = clone;
- for (var i = 0; i < len; ++i) {
+ js.value(obj, '_iN$t', clone, true);
+ objsToClearTmpVar.push(obj);
+ for (let i = 0; i < len; ++i) {
var value = obj[i];
if (typeof value === 'object' && value) {
clone[i] = value._iN$t || instantiateObj(value, parent);
@@ -241,7 +253,6 @@ function instantiateObj (obj, parent) {
clone[i] = value;
}
}
- objsToClearTmpVar.push(obj);
return clone;
}
else if (obj._objFlags & Destroyed) {
diff --git a/cocos2d/core/platform/js.js b/cocos2d/core/platform/js.js
index fbdca5da420..3363184acca 100644
--- a/cocos2d/core/platform/js.js
+++ b/cocos2d/core/platform/js.js
@@ -45,8 +45,8 @@ function _copyprop(name, source, target) {
}
/**
- * This module provides some JavaScript utilities.
- * All members can be accessed with "cc.js".
+ * !#en This module provides some JavaScript utilities. All members can be accessed with `cc.js`.
+ * !#zh 这个模块封装了 JavaScript 相关的一些实用函数,你可以通过 `cc.js` 来访问这个模块。
* @submodule js
* @module js
*/
@@ -221,6 +221,19 @@ var js = {
}
},
+ /**
+ * Checks whether obj is an empty object
+ * @method isEmptyObject
+ * @param {any} obj
+ * @returns {Boolean}
+ */
+ isEmptyObject: function (obj) {
+ for (var key in obj) {
+ return false;
+ }
+ return true;
+ },
+
/**
* Get property descriptor in object and all its ancestors
* @method getPropertyDescriptor
@@ -382,7 +395,16 @@ function isTempClassId (id) {
var _idToClass = {};
var _nameToClass = {};
- function getRegister (key, table) {
+ function setup (key, publicName, table) {
+ js.getset(js, publicName,
+ function () {
+ return Object.assign({}, table);
+ },
+ function (value) {
+ js.clear(table);
+ Object.assign(table, value);
+ }
+ );
return function (id, constructor) {
// deregister old
if (constructor.prototype.hasOwnProperty(key)) {
@@ -418,9 +440,37 @@ cc.js.unregisterClass to remove the id of unused class';
* @param {Function} constructor
* @private
*/
- js._setClassId = getRegister('__cid__', _idToClass);
+ /**
+ * !#en All classes registered in the engine, indexed by ID.
+ * !#zh 引擎中已注册的所有类型,通过 ID 进行索引。
+ * @property _registeredClassIds
+ * @example
+ * // save all registered classes before loading scripts
+ * let builtinClassIds = cc.js._registeredClassIds;
+ * let builtinClassNames = cc.js._registeredClassNames;
+ * // load some scripts that contain CCClass
+ * ...
+ * // clear all loaded classes
+ * cc.js._registeredClassIds = builtinClassIds;
+ * cc.js._registeredClassNames = builtinClassNames;
+ */
+ js._setClassId = setup('__cid__', '_registeredClassIds', _idToClass);
- var doSetClassName = getRegister('__classname__', _nameToClass);
+ /**
+ * !#en All classes registered in the engine, indexed by name.
+ * !#zh 引擎中已注册的所有类型,通过名称进行索引。
+ * @property _registeredClassNames
+ * @example
+ * // save all registered classes before loading scripts
+ * let builtinClassIds = cc.js._registeredClassIds;
+ * let builtinClassNames = cc.js._registeredClassNames;
+ * // load some scripts that contain CCClass
+ * ...
+ * // clear all loaded classes
+ * cc.js._registeredClassIds = builtinClassIds;
+ * cc.js._registeredClassNames = builtinClassNames;
+ */
+ var doSetClassName = setup('__classname__', '_registeredClassNames', _nameToClass);
/**
* Register the class by specified name manually
@@ -514,44 +564,10 @@ cc.js.unregisterClass to remove the id of unused class';
}
return '';
};
-
- if (CC_DEV) {
- js.getset(js, '_registeredClassIds',
- function () {
- var dump = {};
- for (var id in _idToClass) {
- dump[id] = _idToClass[id];
- }
- return dump;
- },
- function (value) {
- js.clear(_idToClass);
- for (var id in value) {
- _idToClass[id] = value[id];
- }
- }
- );
- js.getset(js, '_registeredClassNames',
- function () {
- var dump = {};
- for (var id in _nameToClass) {
- dump[id] = _nameToClass[id];
- }
- return dump;
- },
- function (value) {
- js.clear(_nameToClass);
- for (var id in value) {
- _nameToClass[id] = value[id];
- }
- }
- );
- }
-
})();
/**
- * Defines a polyfill field for obsoleted codes.
+ * Defines a polyfill field for deprecated codes.
* @method obsolete
* @param {any} obj - YourObject or YourClass.prototype
* @param {String} obsoleted - "OldParam" or "YourClass.OldParam"
@@ -564,7 +580,7 @@ js.obsolete = function (obj, obsoleted, newExpr, writable) {
var newProp = extractPropName.exec(newExpr)[0];
function get () {
if (CC_DEV) {
- cc.warnID(5400, obsoleted, newExpr);
+ cc.warnID(1400, obsoleted, newExpr);
}
return this[newProp];
}
@@ -573,7 +589,7 @@ js.obsolete = function (obj, obsoleted, newExpr, writable) {
get,
function (value) {
if (CC_DEV) {
- cc.warnID(5401, obsoleted, newExpr);
+ cc.warnID(1400, obsoleted, newExpr);
}
this[newProp] = value;
}
@@ -627,8 +643,10 @@ js.formatStr = function () {
for (let i = 1; i < argLen; ++i) {
var arg = arguments[i];
var regExpToTest = typeof arg === 'number' ? REGEXP_NUM_OR_STR : REGEXP_STR;
- if (regExpToTest.test(msg))
- msg = msg.replace(regExpToTest, arg);
+ if (regExpToTest.test(msg)) {
+ const notReplaceFunction = '' + arg;
+ msg = msg.replace(regExpToTest, notReplaceFunction);
+ }
else
msg += ' ' + arg;
}
@@ -782,18 +800,6 @@ function appendObjectsAt (array, addObjs, index) {
return array;
}
-/**
- * Exact same function as Array.prototype.indexOf.
- * HACK: ugliy hack for Baidu mobile browser compatibility, stupid Baidu guys modify Array.prototype.indexOf for all pages loaded, their version changes strict comparison to non-strict comparison, it also ignores the second parameter of the original API, and this will cause event handler enter infinite loop.
- * Baidu developers, if you ever see this documentation, here is the standard: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf, Seriously!
- *
- * @method indexOf
- * @param {any} searchElement - Element to locate in the array.
- * @param {Number} [fromIndex=0] - The index to start the search at
- * @return {Number} - the first index at which a given element can be found in the array, or -1 if it is not present.
- */
-var indexOf = Array.prototype.indexOf;
-
/**
* Determines whether the array contains a specific value.
* @method contains
@@ -828,7 +834,6 @@ js.array = {
removeArray,
appendObjectsAt,
copy,
- indexOf,
MutableForwardIterator: require('../utils/mutable-forward-iterator')
};
diff --git a/cocos2d/core/platform/preprocess-class.js b/cocos2d/core/platform/preprocess-class.js
index 89778c4b843..0250bb5f910 100644
--- a/cocos2d/core/platform/preprocess-class.js
+++ b/cocos2d/core/platform/preprocess-class.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -25,13 +25,11 @@
****************************************************************************/
const js = require('./js');
+const Attrs = require('./attribute');
// 增加预处理属性这个步骤的目的是降低 CCClass 的实现难度,将比较稳定的通用逻辑和一些需求比较灵活的属性需求分隔开。
var SerializableAttrs = {
- url: {
- canUsedInGet: true
- },
default: {},
serializable: {},
editorOnly: {},
@@ -67,6 +65,10 @@ function parseNotify (val, propName, notify, properties) {
notify.call(this, oldValue);
};
+ if (CC_EDITOR) {
+ val.notifyFor = newKey;
+ }
+
var newValue = {};
properties[newKey] = newValue;
// 将不能用于get方法中的属性移动到newValue中
@@ -85,117 +87,66 @@ function parseNotify (val, propName, notify, properties) {
}
}
-function checkUrl (val, className, propName, url) {
- if (Array.isArray(url)) {
- if (url.length > 0) {
- url = url[0];
- }
- else if (CC_EDITOR) {
- return cc.errorID(5502, className, propName);
- }
- }
- if (CC_EDITOR) {
- if (url == null) {
- return cc.warnID(5503, className, propName);
- }
- if (typeof url !== 'function' || !js.isChildClassOf(url, cc.RawAsset)) {
- return cc.errorID(5504, className, propName);
- }
- if (url === cc.RawAsset) {
- cc.warn('Please change the definition of property \'%s\' in class \'%s\'. Starting from v1.10,\n' +
- 'the use of declaring a property in CCClass as a URL has been deprecated.\n' +
- 'For example, if property is cc.RawAsset, the previous definition is:\n' +
- ' %s: cc.RawAsset,\n' +
- ' // or:\n' +
- ' %s: {\n' +
- ' url: cc.RawAsset,\n' +
- ' default: ""\n' +
- ' },\n' +
- ' // and the original method to get url is:\n' +
- ' `this.%s`\n' +
- 'Now it should be changed to:\n' +
- ' %s: {\n' +
- ' type: cc.Asset, // use \'type:\' to define Asset object directly\n' +
- ' default: null, // object\'s default value is null\n' +
- ' },\n' +
- ' // and you must get the url by using:\n' +
- ' `this.%s.nativeUrl`\n' +
- '(This helps us to successfully refactor all RawAssets at v2.0, ' +
- 'sorry for the inconvenience. \uD83D\uDE30 )',
- propName, className, propName, propName, propName, propName, propName);
- }
- else if (js.isChildClassOf(url, cc.Asset)) {
- if (cc.RawAsset.wasRawAssetType(url)) {
- if (!val._short) {
- cc.warn('Please change the definition of property \'%s\' in class \'%s\'. Starting from v1.10,\n' +
- 'the use of declaring a property in CCClass as a URL has been deprecated.\n' +
- 'For example, if property is Texture2D, the previous definition is:\n' +
- ' %s: cc.Texture2D,\n' +
- ' // or:\n' +
- ' %s: {\n' +
- ' url: cc.Texture2D,\n' +
- ' default: ""\n' +
- ' },\n' +
- 'Now it should be changed to:\n' +
- ' %s: {\n' +
- ' type: cc.Texture2D, // use \'type:\' to define Texture2D object directly\n' +
- ' default: null, // object\'s default value is null\n' +
- ' },\n' +
- '(This helps us to successfully refactor all RawAssets at v2.0, ' +
- 'sorry for the inconvenience. \uD83D\uDE30 )',
- propName, className, propName, propName, propName);
- }
- }
- else {
- return cc.errorID(5505, className, propName, cc.js.getClassName(url));
- }
- }
- if (val.type) {
- return cc.warnID(5506, className, propName);
- }
- }
- val.type = url;
-}
-
function parseType (val, type, className, propName) {
+ const STATIC_CHECK = (CC_EDITOR && CC_DEV) || CC_TEST;
+
if (Array.isArray(type)) {
- if (CC_EDITOR) {
+ if (STATIC_CHECK && 'default' in val) {
var isArray = require('./CCClass').isArray; // require lazily to avoid circular require() calls
if (!isArray(val.default)) {
cc.warnID(5507, className, propName);
}
}
if (type.length > 0) {
- if (cc.RawAsset.isRawAssetType(type[0])) {
- val.url = type[0];
- delete val.type;
- return;
- }
- else {
- val.type = type = type[0];
- }
+ val.type = type = type[0];
}
else {
return cc.errorID(5508, className, propName);
}
}
- if (CC_EDITOR) {
- if (typeof type === 'function') {
- if (cc.RawAsset.isRawAssetType(type)) {
- cc.warnID(5509, className, propName,
- js.getClassName(type));
+ if (typeof type === 'function') {
+ if (type === String) {
+ val.type = cc.String;
+ if (STATIC_CHECK) {
+ cc.warnID(3608, `"${className}.${propName}"`);
}
}
- else if (type === 'Number') {
- cc.warnID(5510, className, propName);
+ else if (type === Boolean) {
+ val.type = cc.Boolean;
+ if (STATIC_CHECK) {
+ cc.warnID(3609, `"${className}.${propName}"`);
+ }
}
- else if (type == null) {
+ else if (type === Number) {
+ val.type = cc.Float;
+ if (STATIC_CHECK) {
+ cc.warnID(3610, `"${className}.${propName}"`);
+ }
+ }
+ }
+ else if (STATIC_CHECK) {
+ switch (type) {
+ case 'Number':
+ cc.warnID(5510, className, propName);
+ break;
+ case 'String':
+ cc.warn(`The type of "${className}.${propName}" must be cc.String, not "String".`);
+ break;
+ case 'Boolean':
+ cc.warn(`The type of "${className}.${propName}" must be cc.Boolean, not "Boolean".`);
+ break;
+ case 'Float':
+ cc.warn(`The type of "${className}.${propName}" must be cc.Float, not "Float".`);
+ break;
+ case 'Integer':
+ cc.warn(`The type of "${className}.${propName}" must be cc.Integer, not "Integer".`);
+ break;
+ case null:
cc.warnID(5511, className, propName);
+ break;
}
}
-}
-function postCheckType (val, type, className, propName) {
if (CC_EDITOR && typeof type === 'function') {
if (cc.Class._isCCClass(type) && val.serializable !== false && !js._getClassId(type, false)) {
cc.warnID(5512, className, propName, className, propName);
@@ -216,87 +167,37 @@ function getBaseClassWherePropertyDefined_DEV (propName, cls) {
}
}
-exports.getFullFormOfProperty = function (options, propname_dev, classname_dev) {
+function _wrapOptions (isES6Getset, _default, type) {
+ let res = isES6Getset ? { _short: true } : { _short: true, default: _default };
+ if (type) {
+ res.type = type;
+ }
+ return res;
+}
+
+exports.getFullFormOfProperty = function (options, isES6Getset) {
var isLiteral = options && options.constructor === Object;
- if ( !isLiteral ) {
- if (Array.isArray(options) && options.length > 0) {
- var type = options[0];
- if (CC_DEV && cc.RawAsset.wasRawAssetType(type)) {
- // deprecate `myProp: [cc.Texture2D]` since 1.10
- cc.warn('Please change the definition of property \'%s\' in class \'%s\'. Starting from v1.10,\n' +
- 'properties in CCClass can not be abbreviated if they are of type RawAsset.\n' +
- 'Please use the complete form.\n' +
- 'For example, if property is Texture2D\'s url array, the previous definition is:\n' +
- ' %s: [cc.Texture2D],\n' +
- 'Now it should be changed to:\n' +
- ' %s: {\n' +
- ' type: cc.Texture2D, // use \'type:\' to define an array of Texture2D objects\n' +
- ' default: []\n' +
- ' },\n' +
- '(This helps us to successfully refactor all RawAssets at v2.0, ' +
- 'sorry for the inconvenience. \uD83D\uDE30 )',
- propname_dev, classname_dev, propname_dev, propname_dev);
- return {
- default: [],
- url: options,
- _short: true
- };
- }
- return {
- default: [],
- type: options,
- _short: true
- };
- }
- else if (typeof options === 'function') {
- var type = options;
- if (!cc.RawAsset.isRawAssetType(type)) {
- if (cc.RawAsset.wasRawAssetType(type)) {
- // deprecate `myProp: cc.Texture2D` since 1.10
- if (CC_DEV) {
- cc.warn('Please change the definition of property \'%s\' in class \'%s\'. Starting from v1.10,\n' +
- 'properties in CCClass can not be abbreviated if they are of type RawAsset.\n' +
- 'Please use the complete form.\n' +
- 'For example, if the type is Texture2D, the previous definition is:\n' +
- ' %s: cc.Texture2D,\n' +
- 'Now it should be changed to:\n' +
- ' %s: {\n' +
- ' type: cc.Texture2D // use \'type:\' to define Texture2D object directly\n' +
- ' default: null, // object\'s default value is null\n' +
- ' },\n' +
- '(This helps us to successfully refactor all RawAssets at v2.0, ' +
- 'sorry for the inconvenience. \uD83D\uDE30 )',
- propname_dev, classname_dev, propname_dev, propname_dev);
- }
- }
- else {
- return {
- default: js.isChildClassOf(type, cc.ValueType) ? new type() : null,
- type: type,
- _short: true
- };
- }
- }
- return {
- default: '',
- url: type,
- _short: true
- };
- }
- else {
- return {
- default: options,
- _short: true
- };
- }
+ if (isLiteral) {
+ return null;
+ }
+ if (Array.isArray(options) && options.length > 0) {
+ return _wrapOptions(isES6Getset, [], options);
+ }
+ else if (typeof options === 'function') {
+ return _wrapOptions(isES6Getset, js.isChildClassOf(options, cc.ValueType) ? new options() : null, options);
+ }
+ else if (options instanceof Attrs.PrimitiveType) {
+ return _wrapOptions(isES6Getset, options.default);
+ }
+ else {
+ return _wrapOptions(isES6Getset, options);
}
- return null;
};
exports.preprocessAttrs = function (properties, className, cls, es6) {
for (var propName in properties) {
var val = properties[propName];
- var fullForm = exports.getFullFormOfProperty(val, propName, className);
+ var fullForm = exports.getFullFormOfProperty(val, false);
if (fullForm) {
val = properties[propName] = fullForm;
}
@@ -339,14 +240,6 @@ exports.preprocessAttrs = function (properties, className, cls, es6) {
if ('type' in val) {
parseType(val, val.type, className, propName);
}
-
- if ('url' in val) {
- checkUrl(val, className, propName, val.url);
- }
-
- if ('type' in val) {
- postCheckType(val, val.type, className, propName);
- }
}
}
};
diff --git a/cocos2d/core/platform/requiring-frame.js b/cocos2d/core/platform/requiring-frame.js
index 2dadbe13028..2de65ca1c35 100644
--- a/cocos2d/core/platform/requiring-frame.js
+++ b/cocos2d/core/platform/requiring-frame.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/platform/url.js b/cocos2d/core/platform/url.js
deleted file mode 100644
index 9cf37a3abe4..00000000000
--- a/cocos2d/core/platform/url.js
+++ /dev/null
@@ -1,90 +0,0 @@
-/****************************************************************************
- Copyright (c) 2013-2016 Chukong Technologies Inc.
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-/**
- * @class url
- * @static
- */
-cc.url = {
-
- /**
- * The base url of raw assets.
- * @property {Object} _rawAssets
- * @private
- * @readOnly
- */
- _rawAssets: '',
-
- normalize: function (url) {
- if (url) {
- if (url.charCodeAt(0) === 46 && url.charCodeAt(1) === 47) {
- // strip './'
- url = url.slice(2);
- }
- else if (url.charCodeAt(0) === 47) {
- // strip '/'
- url = url.slice(1);
- }
- }
- return url;
- },
-
- /**
- * Returns the url of raw assets, you will only need this if the raw asset is inside the "resources" folder.
- *
- * @method raw
- * @param {String} url
- * @return {String}
- * @example {@link cocos2d/core/platform/url/raw.js}
- */
- raw: function (url) {
- if (CC_EDITOR && !this._rawAssets) {
- cc.errorID(7000);
- return '';
- }
-
- url = this.normalize(url);
-
- if ( !url.startsWith('resources/') ) {
- cc.errorID(CC_EDITOR ? 7001 : 7002, url);
- }
- else {
- // Compatible with versions lower than 1.10
- var uuid = cc.loader._getResUuid(url.slice(10), cc.Asset, true);
- if (uuid) {
- return cc.AssetLibrary.getLibUrlNoExt(uuid, true) + cc.path.extname(url);
- }
- }
-
- return this._rawAssets + url;
- },
-
- _init: function (assets) {
- this._rawAssets = cc.path.stripSep(assets) + '/';
- }
-};
-
-module.exports = cc.url;
diff --git a/cocos2d/core/platform/utils.js b/cocos2d/core/platform/utils.js
index 46312b0277c..dfd6bc3975a 100644
--- a/cocos2d/core/platform/utils.js
+++ b/cocos2d/core/platform/utils.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -25,6 +25,7 @@
****************************************************************************/
// TODO - merge with misc.js
+const js = require('./js');
module.exports = {
contains: function (refNode, otherNode) {
@@ -91,12 +92,8 @@ if (CC_DEV) {
if (!obj || obj.constructor !== Object) {
return false;
}
- // jshint ignore: start
- for (var k in obj) {
- return false;
- }
- // jshint ignore: end
- return true;
+
+ return js.isEmptyObject(obj);
};
module.exports.cloneable_DEV = function (obj) {
return obj &&
@@ -108,7 +105,7 @@ if (CC_DEV) {
if (CC_TEST) {
// editor mocks using in unit tests
if (typeof Editor === 'undefined') {
- Editor = {
+ window.Editor = {
UuidUtils: {
NonUuidMark: '.',
uuid: function () {
diff --git a/cocos2d/core/predefine.js b/cocos2d/core/predefine.js
index e58d98d930b..9552ed5f42d 100644
--- a/cocos2d/core/predefine.js
+++ b/cocos2d/core/predefine.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -33,7 +33,7 @@ require('./platform/CCInputExtension');
require('./event');
require('./platform/CCSys');
require('./platform/CCMacro');
-require('./load-pipeline');
+require('./asset-manager');
require('./CCDirector');
require('./renderer');
diff --git a/cocos2d/core/renderer/assembler-2d.js b/cocos2d/core/renderer/assembler-2d.js
new file mode 100644
index 00000000000..29287a1139a
--- /dev/null
+++ b/cocos2d/core/renderer/assembler-2d.js
@@ -0,0 +1,164 @@
+import Assembler from './assembler';
+import dynamicAtlasManager from './utils/dynamic-atlas/manager';
+import RenderData from './webgl/render-data';
+import { Color } from '../value-types';
+
+export default class Assembler2D extends Assembler {
+ constructor () {
+ super();
+
+ this._renderData = new RenderData();
+ this._renderData.init(this);
+
+ this.initData();
+ this.initLocal();
+ }
+
+ get verticesFloats () {
+ return this.verticesCount * this.floatsPerVert;
+ }
+
+ initData () {
+ let data = this._renderData;
+ data.createQuadData(0, this.verticesFloats, this.indicesCount);
+ }
+ initLocal () {
+ this._local = [];
+ this._local.length = 4;
+ }
+
+ updateColor (comp, color) {
+ let uintVerts = this._renderData.uintVDatas[0];
+ if (!uintVerts) return;
+ color = color != null ? color : comp.node.color._val;
+ let floatsPerVert = this.floatsPerVert;
+ let colorOffset = this.colorOffset;
+ for (let i = colorOffset, l = uintVerts.length; i < l; i += floatsPerVert) {
+ uintVerts[i] = color;
+ }
+ }
+
+ getBuffer () {
+ return cc.renderer._handle._meshBuffer;
+ }
+
+ updateWorldVerts (comp) {
+ let local = this._local;
+ let verts = this._renderData.vDatas[0];
+
+ let matrix = comp.node._worldMatrix;
+ let matrixm = matrix.m,
+ a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
+ tx = matrixm[12], ty = matrixm[13];
+
+ let vl = local[0], vr = local[2],
+ vb = local[1], vt = local[3];
+
+ let floatsPerVert = this.floatsPerVert;
+ let vertexOffset = 0;
+ let justTranslate = a === 1 && b === 0 && c === 0 && d === 1;
+
+ if (justTranslate) {
+ // left bottom
+ verts[vertexOffset] = vl + tx;
+ verts[vertexOffset + 1] = vb + ty;
+ vertexOffset += floatsPerVert;
+ // right bottom
+ verts[vertexOffset] = vr + tx;
+ verts[vertexOffset + 1] = vb + ty;
+ vertexOffset += floatsPerVert;
+ // left top
+ verts[vertexOffset] = vl + tx;
+ verts[vertexOffset + 1] = vt + ty;
+ vertexOffset += floatsPerVert;
+ // right top
+ verts[vertexOffset] = vr + tx;
+ verts[vertexOffset + 1] = vt + ty;
+ } else {
+ let al = a * vl, ar = a * vr,
+ bl = b * vl, br = b * vr,
+ cb = c * vb, ct = c * vt,
+ db = d * vb, dt = d * vt;
+
+ // left bottom
+ verts[vertexOffset] = al + cb + tx;
+ verts[vertexOffset + 1] = bl + db + ty;
+ vertexOffset += floatsPerVert;
+ // right bottom
+ verts[vertexOffset] = ar + cb + tx;
+ verts[vertexOffset + 1] = br + db + ty;
+ vertexOffset += floatsPerVert;
+ // left top
+ verts[vertexOffset] = al + ct + tx;
+ verts[vertexOffset + 1] = bl + dt + ty;
+ vertexOffset += floatsPerVert;
+ // right top
+ verts[vertexOffset] = ar + ct + tx;
+ verts[vertexOffset + 1] = br + dt + ty;
+ }
+ }
+
+ fillBuffers (comp, renderer) {
+ if (renderer.worldMatDirty) {
+ this.updateWorldVerts(comp);
+ }
+
+ let renderData = this._renderData;
+ let vData = renderData.vDatas[0];
+ let iData = renderData.iDatas[0];
+
+ let buffer = this.getBuffer(renderer);
+ let offsetInfo = buffer.request(this.verticesCount, this.indicesCount);
+
+ // buffer data may be realloc, need get reference after request.
+
+ // fill vertices
+ let vertexOffset = offsetInfo.byteOffset >> 2,
+ vbuf = buffer._vData;
+
+ if (vData.length + vertexOffset > vbuf.length) {
+ vbuf.set(vData.subarray(0, vbuf.length - vertexOffset), vertexOffset);
+ } else {
+ vbuf.set(vData, vertexOffset);
+ }
+
+ // fill indices
+ let ibuf = buffer._iData,
+ indiceOffset = offsetInfo.indiceOffset,
+ vertexId = offsetInfo.vertexOffset;
+ for (let i = 0, l = iData.length; i < l; i++) {
+ ibuf[indiceOffset++] = vertexId + iData[i];
+ }
+ }
+
+ packToDynamicAtlas (comp, frame) {
+ if (CC_TEST) return;
+
+ if (!frame._original && dynamicAtlasManager && frame._texture.packable) {
+ let packedFrame = dynamicAtlasManager.insertSpriteFrame(frame);
+ if (packedFrame) {
+ frame._setDynamicAtlasFrame(packedFrame);
+ }
+ }
+ let material = comp._materials[0];
+ if (!material) return;
+
+ if (material.getProperty('texture') !== frame._texture) {
+ // texture was packed to dynamic atlas, should update uvs
+ comp._vertsDirty = true;
+ comp._updateMaterial();
+ }
+ }
+}
+
+cc.js.addon(Assembler2D.prototype, {
+ floatsPerVert: 5,
+
+ verticesCount: 4,
+ indicesCount: 6,
+
+ uvOffset: 2,
+ colorOffset: 4,
+});
+
+cc.Assembler2D = Assembler2D;
diff --git a/cocos2d/core/renderer/assembler-3d.js b/cocos2d/core/renderer/assembler-3d.js
new file mode 100644
index 00000000000..a6fe2f89d0d
--- /dev/null
+++ b/cocos2d/core/renderer/assembler-3d.js
@@ -0,0 +1,47 @@
+import { vfmt3D } from './webgl/vertex-format';
+import Vec3 from '../value-types/vec3';
+
+let vec3_temps = [];
+for (let i = 0; i < 4; i++) {
+ vec3_temps.push(cc.v3());
+}
+
+let Assembler3D = {
+ floatsPerVert: 6,
+
+ uvOffset: 3,
+ colorOffset: 5,
+
+ getBuffer (renderer) {
+ return renderer._meshBuffer3D;
+ },
+
+ getVfmt () {
+ return vfmt3D;
+ },
+
+ updateWorldVerts (comp) {
+ let matrix = comp.node._worldMatrix;
+ let local = this._local;
+ let world = this._renderData.vDatas[0];
+
+ Vec3.set(vec3_temps[0], local[0], local[1], 0);
+ Vec3.set(vec3_temps[1], local[2], local[1], 0);
+ Vec3.set(vec3_temps[2], local[0], local[3], 0);
+ Vec3.set(vec3_temps[3], local[2], local[3], 0);
+
+ let floatsPerVert = this.floatsPerVert;
+ for (let i = 0; i < 4; i++) {
+ let vertex = vec3_temps[i];
+ Vec3.transformMat4(vertex, vertex, matrix);
+
+ let dstOffset = floatsPerVert * i;
+ world[dstOffset] = vertex.x;
+ world[dstOffset+1] = vertex.y;
+ world[dstOffset+2] = vertex.z;
+ }
+ },
+};
+
+cc.Assembler3D = Assembler3D;
+export default Assembler3D;
diff --git a/cocos2d/core/renderer/assembler-pool.js b/cocos2d/core/renderer/assembler-pool.js
new file mode 100644
index 00000000000..f5399dde890
--- /dev/null
+++ b/cocos2d/core/renderer/assembler-pool.js
@@ -0,0 +1,86 @@
+import Pool from '../utils/pool';
+
+let _assemblerId = 0;
+
+function getAssemblerId (assemblerCtor) {
+ if (!Object.getOwnPropertyDescriptor(assemblerCtor, '__assemblerId__')) {
+ assemblerCtor.__assemblerId__ = ++_assemblerId;
+ }
+ return assemblerCtor.__assemblerId__;
+}
+
+/**
+ * {
+ * assembler_ctor_id: []
+ * }
+ */
+class AssemblerPool extends Pool {
+ _pool = {};
+
+ put (assembler) {
+ if (!assembler) return;
+ if (!this.enabled) {
+ if (CC_JSB && CC_NATIVERENDERER) {
+ assembler.destroy && assembler.destroy();
+ }
+ return;
+ }
+
+ let id = getAssemblerId(assembler.constructor);
+ let pool = this._pool;
+ if (!pool[id]) {
+ pool[id] = [];
+ }
+ if (this.count > this.maxSize) return;
+
+ this._clean(assembler);
+ pool[id].push(assembler);
+ this.count++;
+ }
+
+ get (assemblerCtor) {
+ let assembler;
+
+ if (this.enabled) {
+ let pool = this._pool;
+ let id = getAssemblerId(assemblerCtor);
+ assembler = pool[id] && pool[id].pop();
+ }
+
+ if (!assembler) {
+ assembler = new assemblerCtor();
+ }
+ else {
+ this.count--;
+ }
+ return assembler;
+ }
+
+ clear () {
+ if (CC_JSB && CC_NATIVERENDERER) {
+ let pool = this._pool;
+ for (let name in pool) {
+ let assemblers = pool[name];
+ if (!assemblers) continue;
+
+ for (let i = 0; i < assemblers.length; i++) {
+ assemblers[i].destroy && assemblers[i].destroy();
+ }
+ }
+ }
+
+ this._pool = {};
+ this.count = 0;
+ }
+
+ _clean (assembler) {
+ if (CC_JSB && CC_NATIVERENDERER) {
+ assembler.reset();
+ }
+ assembler._renderComp = null;
+ }
+}
+
+let pool = new AssemblerPool();
+Pool.register('assembler', pool);
+export default pool;
diff --git a/cocos2d/core/renderer/assembler.js b/cocos2d/core/renderer/assembler.js
new file mode 100644
index 00000000000..b2cafd0ced6
--- /dev/null
+++ b/cocos2d/core/renderer/assembler.js
@@ -0,0 +1,50 @@
+import { vfmtPosUvColor } from './webgl/vertex-format';
+import assemblerPool from './assembler-pool';
+
+export default class Assembler {
+ constructor () {
+ this._extendNative && this._extendNative();
+ }
+ init (renderComp) {
+ this._renderComp = renderComp;
+ }
+
+ updateRenderData (comp) {
+ }
+
+ fillBuffers (comp, renderer) {
+ }
+
+ getVfmt () {
+ return vfmtPosUvColor;
+ }
+}
+
+
+Assembler.register = function (renderCompCtor, assembler) {
+ renderCompCtor.__assembler__ = assembler;
+};
+
+Assembler.init = function (renderComp) {
+ let renderCompCtor = renderComp.constructor;
+ let assemblerCtor = renderCompCtor.__assembler__;
+ while (!assemblerCtor) {
+ renderCompCtor = renderCompCtor.$super;
+ if (!renderCompCtor) {
+ cc.warn(`Can not find assembler for render component : [${cc.js.getClassName(renderComp)}]`);
+ return;
+ }
+ assemblerCtor = renderCompCtor.__assembler__;
+ }
+ if (assemblerCtor.getConstructor) {
+ assemblerCtor = assemblerCtor.getConstructor(renderComp);
+ }
+
+ if (!renderComp._assembler || renderComp._assembler.constructor !== assemblerCtor) {
+ let assembler = assemblerPool.get(assemblerCtor);
+ assembler.init(renderComp);
+ renderComp._assembler = assembler;
+ }
+};
+
+cc.Assembler = Assembler;
diff --git a/cocos2d/core/renderer/canvas/Device.js b/cocos2d/core/renderer/canvas/Device.js
new file mode 100644
index 00000000000..75452ff1b21
--- /dev/null
+++ b/cocos2d/core/renderer/canvas/Device.js
@@ -0,0 +1,94 @@
+
+// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+var Device = function Device(canvasEL) {
+ var ctx;
+
+ try {
+ ctx = canvasEL.getContext('2d');
+ } catch (err) {
+ console.error(err);
+ return;
+ }
+
+ // statics
+ this._canvas = canvasEL;
+ this._ctx = ctx;
+ this._caps = {}; // capability
+ this._stats = {
+ drawcalls: 0,
+ };
+
+ // runtime
+ this._vx = this._vy = this._vw = this._vh = 0;
+ this._sx = this._sy = this._sw = this._sh = 0;
+};
+
+Device.prototype._restoreTexture = function _restoreTexture (unit) {
+};
+
+// ===============================
+// Immediate Settings
+// ===============================
+
+/**
+ * @method setViewport
+ * @param {Number} x
+ * @param {Number} y
+ * @param {Number} w
+ * @param {Number} h
+ */
+Device.prototype.setViewport = function setViewport (x, y, w, h) {
+ if (
+ this._vx !== x ||
+ this._vy !== y ||
+ this._vw !== w ||
+ this._vh !== h
+ ) {
+ this._vx = x;
+ this._vy = y;
+ this._vw = w;
+ this._vh = h;
+ }
+};
+
+/**
+ * @method setScissor
+ * @param {Number} x
+ * @param {Number} y
+ * @param {Number} w
+ * @param {Number} h
+ */
+Device.prototype.setScissor = function setScissor (x, y, w, h) {
+ if (
+ this._sx !== x ||
+ this._sy !== y ||
+ this._sw !== w ||
+ this._sh !== h
+ ) {
+ this._sx = x;
+ this._sy = y;
+ this._sw = w;
+ this._sh = h;
+ }
+};
+
+Device.prototype.clear = function clear (color) {
+ var ctx = this._ctx;
+ ctx.clearRect(this._vx, this._vy, this._vw, this._vh);
+ if (color && (color[0] !== 0 || color[1] !== 0 || color[2] !== 0)) {
+ ctx.fillStyle = 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] +')';
+ ctx.globalAlpha = color[3];
+ ctx.fillRect(this._vx, this._vy, this._vw, this._vh);
+ }
+};
+
+Device.prototype.resetDrawCalls = function () {
+ this._stats.drawcalls = 0;
+}
+
+Device.prototype.getDrawCalls = function () {
+ return this._stats.drawcalls;
+}
+
+module.exports = Device;
diff --git a/cocos2d/core/renderer/canvas/Texture2D.js b/cocos2d/core/renderer/canvas/Texture2D.js
new file mode 100644
index 00000000000..8bda7d7f6a7
--- /dev/null
+++ b/cocos2d/core/renderer/canvas/Texture2D.js
@@ -0,0 +1,41 @@
+
+// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+var Texture2D = function Texture2D(device, options) {
+ this._device = device;
+
+ this._width = 4;
+ this._height = 4;
+
+ this._image = null;
+
+ if (options) {
+ if (options.width !== undefined) {
+ this._width = options.width;
+ }
+ if (options.height !== undefined) {
+ this._height = options.height;
+ }
+
+ this.updateImage(options);
+ }
+};
+
+Texture2D.prototype.update = function update (options) {
+ this.updateImage(options);
+};
+
+Texture2D.prototype.updateImage = function updateImage (options) {
+ if (options.images && options.images[0]) {
+ var image = options.images[0];
+ if (image && image !== this._image) {
+ this._image = image;
+ }
+ }
+};
+
+Texture2D.prototype.destroy = function destroy () {
+ this._image = null;
+};
+
+module.exports = Texture2D;
diff --git a/cocos2d/core/renderer/canvas/forward-renderer.js b/cocos2d/core/renderer/canvas/forward-renderer.js
index 64c4a149d09..4c4fbc72b22 100644
--- a/cocos2d/core/renderer/canvas/forward-renderer.js
+++ b/cocos2d/core/renderer/canvas/forward-renderer.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -29,7 +29,7 @@ let ForwardRenderer = function () {
ForwardRenderer.prototype = {
constructor: ForwardRenderer,
- _reset () {
+ clear () {
},
diff --git a/cocos2d/core/renderer/canvas/index.js b/cocos2d/core/renderer/canvas/index.js
index a89c2fcbb00..9542c0f4bf6 100644
--- a/cocos2d/core/renderer/canvas/index.js
+++ b/cocos2d/core/renderer/canvas/index.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -23,8 +23,12 @@
THE SOFTWARE.
****************************************************************************/
-module.exports = {
- ForwardRenderer: require('./forward-renderer'),
- RenderComponentWalker: require('./canvas-render-walker'),
- _renderers: require('./renderers')
-};
\ No newline at end of file
+import './render-flow';
+import './renderers';
+import ForwardRenderer from './forward-renderer';
+import RenderComponentHandle from './render-component-handle';
+
+export default {
+ ForwardRenderer,
+ RenderComponentHandle
+};
diff --git a/cocos2d/core/renderer/canvas/canvas-render-walker.js b/cocos2d/core/renderer/canvas/render-component-handle.js
similarity index 74%
rename from cocos2d/core/renderer/canvas/canvas-render-walker.js
rename to cocos2d/core/renderer/canvas/render-component-handle.js
index 42f7b7b9550..4975e367c47 100644
--- a/cocos2d/core/renderer/canvas/canvas-render-walker.js
+++ b/cocos2d/core/renderer/canvas/render-component-handle.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -23,11 +23,9 @@
THE SOFTWARE.
****************************************************************************/
-const js = require('../../platform/js');
-const RenderFlow = require('../render-flow');
-require('./renderers');
+const utils = require('./renderers/utils')
-let RenderComponentWalker = function (device, defaultCamera) {
+let RenderComponentHandle = function (device, defaultCamera) {
this._device = device;
// let vx = this._device._vx;
// let vy = this._device._vy;
@@ -37,36 +35,29 @@ let RenderComponentWalker = function (device, defaultCamera) {
this.parentOpacity = 1;
this.parentOpacityDirty = 0;
this.worldMatDirty = 0;
-
- RenderFlow.init(this);
+ this.walking = false;
};
-RenderComponentWalker.prototype = {
- constructor: RenderComponentWalker,
+RenderComponentHandle.prototype = {
+ constructor: RenderComponentHandle,
- reset() {},
-
- _commitComp (comp, assembler) {
- let ctx = this._device._ctx;
- let cam = this._camera;
- ctx.setTransform(cam.a, cam.b, cam.c, cam.d, cam.tx, cam.ty);
- ctx.scale(1, -1);
- assembler.draw(ctx, comp);
- },
-
- visit (scene) {
+ reset() {
let ctx = this._device._ctx;
let canvas = this._device._canvas;
- let color = cc.Camera.main.backgroundColor;
+ var color = cc.Camera.main ? cc.Camera.main.backgroundColor : cc.color();
let rgba = `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a/255})`;
ctx.fillStyle = rgba;
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillRect(0, 0, canvas.width, canvas.height);
this._device._stats.drawcalls = 0;
+ //reset cache data
+ utils.context.reset();
+ },
+
+ terminate () {
- RenderFlow.render(scene);
}
};
-module.exports = RenderComponentWalker;
\ No newline at end of file
+module.exports = RenderComponentHandle;
\ No newline at end of file
diff --git a/cocos2d/core/renderer/canvas/render-flow.js b/cocos2d/core/renderer/canvas/render-flow.js
new file mode 100644
index 00000000000..30da4bafab5
--- /dev/null
+++ b/cocos2d/core/renderer/canvas/render-flow.js
@@ -0,0 +1,46 @@
+/****************************************************************************
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import RenderFlow from '../render-flow';
+
+RenderFlow.prototype._draw = function (node, func) {
+ let batcher = RenderFlow.getBachther();
+ let ctx = batcher._device._ctx;
+ let cam = batcher._camera;
+ ctx.setTransform(cam.a, cam.b, cam.c, cam.d, cam.tx, cam.ty);
+ ctx.scale(1, -1);
+
+ let comp = node._renderComponent;
+ comp._assembler[func](ctx, comp);
+ this._next._func(node);
+}
+
+RenderFlow.prototype._render = function (node) {
+ this._draw(node, 'draw');
+}
+
+RenderFlow.prototype._postRender = function (node) {
+ this._draw(node, 'postDraw');
+}
diff --git a/cocos2d/core/renderer/canvas/renderers/graphics/impl.js b/cocos2d/core/renderer/canvas/renderers/graphics/impl.js
index 92092057f25..81f0885a700 100644
--- a/cocos2d/core/renderer/canvas/renderers/graphics/impl.js
+++ b/cocos2d/core/renderer/canvas/renderers/graphics/impl.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -26,7 +26,6 @@
const Helper = require('../../../../graphics/helper');
const Types = require('../../../../graphics/types');
const js = require('../../../../platform/js');
-const PointFlags = Types.PointFlags;
const LineJoin = Types.LineJoin;
const LineCap = Types.LineCap;
@@ -156,4 +155,5 @@ js.set(_proto, 'miterLimit', function (v) {
this.style.miterLimit = v;
});
+cc.Graphics._Impl = Impl;
module.exports = Impl;
diff --git a/cocos2d/core/renderer/canvas/renderers/graphics/index.js b/cocos2d/core/renderer/canvas/renderers/graphics/index.js
index ac8c5612c24..a7d100d2544 100644
--- a/cocos2d/core/renderer/canvas/renderers/graphics/index.js
+++ b/cocos2d/core/renderer/canvas/renderers/graphics/index.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -22,20 +22,22 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
+import Assembler from '../../../assembler';
+import Impl from './impl';
+import Graphics from '../../../../graphics/graphics';
-const Impl = require('./impl');
+export default class CanvasGraphicsAssembler {
+ init () {}
-module.exports = {
- createImpl () {
- return new Impl();
- },
+ updateRenderData () {}
draw (ctx, comp) {
let node = comp.node;
// Transform
let matrix = node._worldMatrix;
- let a = matrix.m00, b = matrix.m01, c = matrix.m04, d = matrix.m05,
- tx = matrix.m12, ty = matrix.m13;
+ let matrixm = matrix.m;
+ let a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
+ tx = matrixm[12], ty = matrixm[13];
ctx.transform(a, b, c, d, tx, ty);
ctx.save();
@@ -76,13 +78,17 @@ module.exports = {
ctx.restore();
return 1;
- },
+ }
stroke (comp) {
comp._impl.stroke();
- },
+ }
fill (comp) {
comp._impl.fill();
}
+
+ clear () {}
}
+
+Assembler.register(Graphics, CanvasGraphicsAssembler);
diff --git a/cocos2d/core/renderer/canvas/renderers/index.js b/cocos2d/core/renderer/canvas/renderers/index.js
index 2e10cbe8b21..4d6baf73aec 100644
--- a/cocos2d/core/renderer/canvas/renderers/index.js
+++ b/cocos2d/core/renderer/canvas/renderers/index.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -23,42 +23,12 @@
THE SOFTWARE.
****************************************************************************/
-let js = require('../../../platform/js');
+import '../../../components/CCSprite';
+import '../../../components/CCLabel';
+import '../../../components/CCMask';
+import '../../../graphics/graphics';
-let Sprite = require('../../../components/CCSprite');
-let Label = require('../../../components/CCLabel');
-let Mask = require('../../../components/CCMask');
-let Graphics = require('../../../graphics/graphics');
-
-let spriteRenderer = require('./sprite');
-let labelRenderer = require('./label');
-let graphicsRenderer = require('./graphics');
-let maskRenderer = require('./mask');
-
-let map = {};
-let postMap = {};
-
-function addRenderer (Component, handler, postHandler) {
- let name = js.getClassName(Component);
- map[name] = handler;
- if (postHandler) {
- postMap[name] = postHandler;
- }
- Component._assembler = handler;
- Component._postAssembler = postHandler;
-}
-
-addRenderer(Sprite, spriteRenderer);
-addRenderer(Label, labelRenderer);
-if (Mask) {
- addRenderer(Mask, maskRenderer.beforeHandler, maskRenderer.afterHandler);
-}
-if (Graphics) {
- addRenderer(Graphics, graphicsRenderer);
-}
-
-module.exports = {
- map,
- postMap,
- addRenderer
-};
\ No newline at end of file
+import './sprite';
+import './label';
+import './graphics';
+import './mask';
diff --git a/cocos2d/core/renderer/canvas/renderers/label/bmfont.js b/cocos2d/core/renderer/canvas/renderers/label/bmfont.js
index 35080ebfd19..ff7fda65fb2 100644
--- a/cocos2d/core/renderer/canvas/renderers/label/bmfont.js
+++ b/cocos2d/core/renderer/canvas/renderers/label/bmfont.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -23,23 +23,24 @@
THE SOFTWARE.
****************************************************************************/
-const bmfontUtils = require('../../../utils/label/bmfont')
-const js = require('../../../../platform/js');
-const utils = require('../utils');
+import BmfontAssembler from '../../../utils/label/bmfont';
+import RenderData from '../render-data';
+import utils from '../utils';
-module.exports = js.addon({
- createData (comp) {
- return comp.requestRenderData();
- },
+export default class CanvasBmfontAssembler extends BmfontAssembler {
+ init () {
+ this._renderData = new RenderData();
+ }
+
+ updateColor () {}
- appendQuad (renderData, texture, rect, rotated, x, y, scale) {
+ appendQuad (comp, texture, rect, rotated, x, y, scale) {
+ let renderData = this._renderData;
let dataOffset = renderData.dataLength;
renderData.dataLength += 2;
- let data = renderData._data;
- let texw = texture.width,
- texh = texture.height;
+ let verts = renderData.vertices;
let rectWidth = rect.width,
rectHeight = rect.height;
@@ -51,58 +52,59 @@ module.exports = js.addon({
b = rect.y;
t = rect.y + rectHeight;
- data[dataOffset].u = l;
- data[dataOffset].v = b;
- data[dataOffset+1].u = r;
- data[dataOffset+1].v = t;
+ verts[dataOffset].u = l;
+ verts[dataOffset].v = b;
+ verts[dataOffset+1].u = r;
+ verts[dataOffset+1].v = t;
} else {
l = rect.x;
r = rect.x + rectHeight;
b = rect.y;
t = rect.y + rectWidth;
- data[dataOffset].u = l;
- data[dataOffset].v = t;
- data[dataOffset+1].u = l;
- data[dataOffset+1].v = b;
+ verts[dataOffset].u = l;
+ verts[dataOffset].v = t;
+ verts[dataOffset+1].u = l;
+ verts[dataOffset+1].v = b;
}
- data[dataOffset].x = x;
- data[dataOffset].y = y - rectHeight * scale;
- data[dataOffset+1].x = x + rectWidth * scale;
- data[dataOffset+1].y = y;
- },
+ verts[dataOffset].x = x;
+ verts[dataOffset].y = y - rectHeight * scale;
+ verts[dataOffset+1].x = x + rectWidth * scale;
+ verts[dataOffset+1].y = y;
+ }
draw (ctx, comp) {
let node = comp.node;
// Transform
let matrix = node._worldMatrix;
- let a = matrix.m00, b = matrix.m01, c = matrix.m04, d = matrix.m05,
- tx = matrix.m12, ty = matrix.m13;
+ let matrixm = matrix.m;
+ let a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
+ tx = matrixm[12], ty = matrixm[13];
ctx.transform(a, b, c, d, tx, ty);
ctx.scale(1, -1);
// TODO: handle blend function
// opacity
- ctx.globalAlpha = node.opacity / 255;
+ utils.context.setGlobalAlpha(ctx, node.opacity / 255);
- let tex = comp._texture,
- data = comp._renderData._data;
+ let tex = comp._frame._texture,
+ verts = this._renderData.vertices;
- let image = tex.getHtmlElementObj();
+ let image = utils.getColorizedImage(tex, node._color);
- for (let i = 0, l = data.length; i < l; i+=2) {
- let x = data[i].x;
- let y = data[i].y;
- let w = data[i+1].x - x;
- let h = data[i+1].y - y;
+ for (let i = 0, l = verts.length; i < l; i+=2) {
+ let x = verts[i].x;
+ let y = verts[i].y;
+ let w = verts[i+1].x - x;
+ let h = verts[i+1].y - y;
y = - y - h;
- let sx = data[i].u;
- let sy = data[i].v;
- let sw = data[i+1].u - sx;
- let sh = data[i+1].v - sy;
+ let sx = verts[i].u;
+ let sy = verts[i].v;
+ let sw = verts[i+1].u - sx;
+ let sh = verts[i+1].v - sy;
ctx.drawImage(image,
sx, sy, sw, sh,
@@ -111,4 +113,5 @@ module.exports = js.addon({
return 1;
}
-}, bmfontUtils);
+}
+
diff --git a/cocos2d/core/renderer/canvas/renderers/label/index.js b/cocos2d/core/renderer/canvas/renderers/label/index.js
index bd98ca59970..c9dec63257a 100644
--- a/cocos2d/core/renderer/canvas/renderers/label/index.js
+++ b/cocos2d/core/renderer/canvas/renderers/label/index.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -23,34 +23,54 @@
THE SOFTWARE.
****************************************************************************/
-const ttf = require('./ttf');
-const bmfont = require('./bmfont');
+import Assembler from '../../../assembler';
+import Label from '../../../../components/CCLabel';
+import TTF from './ttf';
+import Bmfont from './bmfont';
-module.exports = {
- getAssembler (comp) {
- let assembler = ttf;
-
- if (comp.font instanceof cc.BitmapFont) {
- assembler = bmfont;
+let canvasPool = {
+ pool: [],
+ get () {
+ let data = this.pool.pop();
+
+ if (!data) {
+ let canvas = document.createElement("canvas");
+ let context = canvas.getContext("2d");
+ data = {
+ canvas: canvas,
+ context: context
+ }
+
+ // default text info
+ context.textBaseline = 'alphabetic';
}
- return assembler;
+ return data;
},
+ put (canvas) {
+ if (this.pool.length >= 32) {
+ return;
+ }
+ this.pool.push(canvas);
+ }
+};
- createData (comp) {
- return comp._assembler.createData(comp);
- },
+Label._canvasPool = canvasPool;
- draw (ctx, comp) {
- // Check whether need to render
- if (!comp._texture) {
- return 0;
- }
- let assembler = comp._assembler;
- if (!assembler) return 0;
+Assembler.register(Label, {
+ getConstructor(label) {
+ let ctor = TTF;
- assembler.updateRenderData(comp);
- return assembler.draw(ctx, comp);
- }
-};
\ No newline at end of file
+ if (label.font instanceof cc.BitmapFont) {
+ ctor = Bmfont;
+ } else if (label.cacheMode === Label.CacheMode.CHAR) {
+ cc.warn('sorry, canvas mode does not support CHAR mode currently!');
+ }
+
+ return ctor;
+ },
+
+ TTF,
+ Bmfont
+});
\ No newline at end of file
diff --git a/cocos2d/core/renderer/canvas/renderers/label/ttf.js b/cocos2d/core/renderer/canvas/renderers/label/ttf.js
index 08094b71840..b4aab89e9dc 100644
--- a/cocos2d/core/renderer/canvas/renderers/label/ttf.js
+++ b/cocos2d/core/renderer/canvas/renderers/label/ttf.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -23,20 +23,21 @@
THE SOFTWARE.
****************************************************************************/
-const ttfUtils = require('../../../utils/label/ttf')
-const js = require('../../../../platform/js');
-const utils = require('../utils');
+import TTFAssembler from '../../../utils/label/ttf';
+import RenderData from '../render-data';
+import utils from '../utils';
-module.exports = js.addon({
- createData (sprite) {
- let renderData = sprite.requestRenderData();
- // 0 for bottom left, 1 for top right
- renderData.dataLength = 2;
- return renderData;
- },
+export default class CanvasTTFAssembler extends TTFAssembler {
+ init () {
+ this._renderData = new RenderData();
+ this._renderData.dataLength = 2;
+ }
+
+ updateColor () {
+ }
- _updateVerts (comp) {
- let renderData = comp._renderData;
+ updateVerts (comp) {
+ let renderData = this._renderData;
let node = comp.node,
width = node.width,
@@ -44,44 +45,46 @@ module.exports = js.addon({
appx = node.anchorX * width,
appy = node.anchorY * height;
- let data = renderData._data;
- data[0].x = -appx;
- data[0].y = -appy;
- data[1].x = width - appx;
- data[1].y = height - appy;
- },
+ let verts = renderData.vertices;
+ verts[0].x = -appx;
+ verts[0].y = -appy;
+ verts[1].x = width - appx;
+ verts[1].y = height - appy;
+ }
_updateTexture (comp) {
- ttfUtils._updateTexture(comp);
- utils.dropColorizedImage(comp._texture, comp.node.color);
- },
+ TTFAssembler.prototype._updateTexture.call(this, comp);
+ let texture = comp._frame._texture;
+ utils.dropColorizedImage(texture, comp.node.color);
+ }
draw (ctx, comp) {
let node = comp.node;
// Transform
let matrix = node._worldMatrix;
- let a = matrix.m00, b = matrix.m01, c = matrix.m04, d = matrix.m05,
- tx = matrix.m12, ty = matrix.m13;
+ let matrixm = matrix.m;
+ let a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
+ tx = matrixm[12], ty = matrixm[13];
ctx.transform(a, b, c, d, tx, ty);
ctx.scale(1, -1);
// TODO: handle blend function
// opacity
- ctx.globalAlpha = node.opacity / 255;
+ utils.context.setGlobalAlpha(ctx, node.opacity / 255);
- let tex = comp._texture,
- data = comp._renderData._data;
+ let tex = comp._frame._texture,
+ verts = this._renderData.vertices;
let image = tex.getHtmlElementObj();
- let x = data[0].x;
- let y = data[0].y;
- let w = data[1].x - x;
- let h = data[1].y - y;
+ let x = verts[0].x;
+ let y = verts[0].y;
+ let w = verts[1].x - x;
+ let h = verts[1].y - y;
y = - y - h;
ctx.drawImage(image, x, y, w, h);
return 1;
}
-}, ttfUtils);
+}
diff --git a/cocos2d/core/renderer/canvas/renderers/mask.js b/cocos2d/core/renderer/canvas/renderers/mask.js
index ccb82cc9bc5..e6087778480 100644
--- a/cocos2d/core/renderer/canvas/renderers/mask.js
+++ b/cocos2d/core/renderer/canvas/renderers/mask.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -25,28 +25,21 @@
const Mask = require('../../../components/CCMask');
const graphicsHandler = require('./graphics');
+import Assembler from '../../assembler';
-let beforeHandler = {
- updateRenderData (comp) {},
-
+export default class CanvasMaskAssembler extends Assembler {
draw (ctx, mask) {
ctx.save();
// draw stencil
- graphicsHandler.draw(ctx, mask._graphics);
+ mask._graphics._assembler.draw(ctx, mask._graphics);
ctx.clip();
}
-};
-let afterHandler = {
- updateRenderData (comp) {},
- draw (ctx, mask) {
+ postDraw (ctx, mask) {
ctx.restore();
}
-};
+}
-module.exports = {
- beforeHandler,
- afterHandler
-};
\ No newline at end of file
+Assembler.register(Mask, CanvasMaskAssembler);
diff --git a/cocos2d/core/renderer/canvas/renderers/render-data.js b/cocos2d/core/renderer/canvas/renderers/render-data.js
new file mode 100644
index 00000000000..cba03f7076c
--- /dev/null
+++ b/cocos2d/core/renderer/canvas/renderers/render-data.js
@@ -0,0 +1,22 @@
+
+export default class RenderData {
+ constructor () {
+ this.vertices = [];
+ }
+
+ get dataLength () {
+ return this.vertices.length;
+ }
+ set dataLength (v) {
+ let old = this.vertices.length;
+ this.vertices.length = v;
+ for (let i = old; i < v; i++) {
+ this.vertices[i] = {
+ x: 0.0,
+ y: 0.0,
+ u: 0.0,
+ v: 0.0,
+ };
+ }
+ }
+}
diff --git a/cocos2d/core/renderer/canvas/renderers/sprite/index.js b/cocos2d/core/renderer/canvas/renderers/sprite/index.js
index 0e7b137e63a..7b4cd6f56b6 100644
--- a/cocos2d/core/renderer/canvas/renderers/sprite/index.js
+++ b/cocos2d/core/renderer/canvas/renderers/sprite/index.js
@@ -1,55 +1,28 @@
-/****************************************************************************
- Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
+import Asembler from '../../../assembler';
+import { Type } from '../../../../components/CCSprite';
- http://www.cocos.com
+import Simple from "./simple";
+import Sliced from "./sliced";
+import Tiled from "./tiled";
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-const Sprite = require('../../../../components/CCSprite');
-const SpriteType = Sprite.Type;
-const FillType = Sprite.FillType;
-let simple = require('./simple');
-let sliced = require('./sliced');
-let tiled = require('./tiled');
-
-module.exports = {
- getAssembler: function (sprite) {
+let ctor = {
+ getConstructor(sprite) {
+ let ctor = Simple;
switch (sprite.type) {
- case SpriteType.SIMPLE:
- return simple;
- case SpriteType.SLICED:
- return sliced;
- case SpriteType.TILED:
- return tiled;
- case SpriteType.FILLED:
- if (sprite._fillType === FillType.RADIAL) {
- return null;
- }
- else {
- return null;
- }
+ case Type.SLICED:
+ ctor = Sliced;
+ break;
+ case Type.TILED:
+ ctor = Tiled;
+ break;
}
+
+ return ctor;
},
- createData (sprite) {
- return sprite._assembler.createData(sprite);
- }
-};
\ No newline at end of file
+ Simple,
+ Sliced,
+ Tiled
+};
+
+Asembler.register(cc.Sprite, ctor);
diff --git a/cocos2d/core/renderer/canvas/renderers/sprite/simple.js b/cocos2d/core/renderer/canvas/renderers/sprite/simple.js
index 18031b3b52c..999bc34ca2f 100644
--- a/cocos2d/core/renderer/canvas/renderers/sprite/simple.js
+++ b/cocos2d/core/renderer/canvas/renderers/sprite/simple.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -23,67 +23,57 @@
THE SOFTWARE.
****************************************************************************/
+import Assembler from '../../../assembler';
+import RenderData from '../render-data';
const utils = require('../utils');
-let renderer = {
-
- createData (sprite) {
- let renderData = sprite.requestRenderData();
- // 0 for bottom left, 1 for top right
- renderData.dataLength = 2;
- return renderData;
- },
+export default class CanvasSimpleSprite extends Assembler {
+ init () {
+ this._renderData = new RenderData();
+ this._renderData.dataLength = 2;
+ }
updateRenderData (sprite) {
- if (!sprite._material) {
- sprite._activateMaterial();
- }
-
- let renderData = sprite._renderData;
- if (renderData.uvDirty) {
+ if (sprite._vertsDirty) {
this.updateUVs(sprite);
- }
-
- if (renderData.vertDirty) {
this.updateVerts(sprite);
+ sprite._vertsDirty = false;
}
- },
+ }
updateUVs (sprite) {
let frame = sprite.spriteFrame;
- let renderData = sprite._renderData;
- let data = renderData._data;
+ let renderData = this._renderData;
+ let verts = renderData.vertices;
let rect = frame._rect;
- let texture = frame._texture;
if (frame._rotated) {
let l = rect.x;
- let r = rect.height;
+ let r = rect.width;
let b = rect.y;
- let t = rect.width;
- data[0].u = l;
- data[0].v = t;
- data[1].u = r;
- data[1].v = b;
+ let t = rect.height;
+ verts[0].u = l;
+ verts[0].v = b;
+ verts[1].u = t;
+ verts[1].v = r;
}
else {
let l = rect.x;
let r = rect.width;
let b = rect.y;
let t = rect.height;
- data[0].u = l;
- data[0].v = b;
- data[1].u = r;
- data[1].v = t;
+ verts[0].u = l;
+ verts[0].v = b;
+ verts[1].u = r;
+ verts[1].v = t;
}
-
- renderData.uvDirty = false;
- },
+ }
updateVerts (sprite) {
- let renderData = sprite._renderData,
+ let renderData = this._renderData,
node = sprite.node,
- data = renderData._data,
+ verts = renderData.vertices,
+ frame = sprite.spriteFrame,
cw = node.width, ch = node.height,
appx = node.anchorX * cw, appy = node.anchorY * ch,
l, b, r, t;
@@ -94,64 +84,72 @@ let renderer = {
t = ch;
}
else {
- let frame = sprite.spriteFrame,
- ow = frame._originalSize.width, oh = frame._originalSize.height,
+ let ow = frame._originalSize.width, oh = frame._originalSize.height,
rw = frame._rect.width, rh = frame._rect.height,
offset = frame._offset,
scaleX = cw / ow, scaleY = ch / oh;
let trimLeft = offset.x + (ow - rw) / 2;
- let trimRight = offset.x - (ow - rw) / 2;
let trimBottom = offset.y + (oh - rh) / 2;
- let trimTop = offset.y - (oh - rh) / 2;
l = trimLeft * scaleX - appx;
b = trimBottom * scaleY - appy;
r = cw;
t = ch;
}
- data[0].x = l;
- data[0].y = b;
- data[1].x = r;
- data[1].y = t;
-
+ if (frame._rotated) {
+ verts[0].y = l;
+ verts[0].x = b;
+ verts[1].y = r;
+ verts[1].x = t;
+ } else {
+ verts[0].x = l;
+ verts[0].y = b;
+ verts[1].x = r;
+ verts[1].y = t;
+ }
+
renderData.vertDirty = false;
- },
+ }
draw (ctx, comp) {
let node = comp.node;
+ let frame = comp._spriteFrame;
// Transform
let matrix = node._worldMatrix;
- let a = matrix.m00, b = matrix.m01, c = matrix.m04, d = matrix.m05,
- tx = matrix.m12, ty = matrix.m13;
+ let matrixm = matrix.m;
+ let a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
+ tx = matrixm[12], ty = matrixm[13];
ctx.transform(a, b, c, d, tx, ty);
ctx.scale(1, -1);
+ if (frame._rotated) {
+ ctx.rotate(- Math.PI / 2);
+ }
// TODO: handle blend function
// opacity
- ctx.globalAlpha = node.opacity / 255;
+ utils.context.setGlobalAlpha(ctx, node.opacity / 255);
- let tex = comp._spriteFrame._texture,
- data = comp._renderData._data;
+ let tex = frame._texture,
+ verts = this._renderData.vertices;
let image = utils.getColorizedImage(tex, node._color);
- let x = data[0].x;
- let y = data[0].y;
- let w = data[1].x;
- let h = data[1].y;
+ let x = verts[0].x;
+ let y = verts[0].y;
+ let w = verts[1].x;
+ let h = verts[1].y;
y = - y - h;
- let sx = data[0].u;
- let sy = data[0].v;
- let sw = data[1].u;
- let sh = data[1].v;
+ let sx = verts[0].u;
+ let sy = verts[0].v;
+ let sw = verts[1].u;
+ let sh = verts[1].v;
ctx.drawImage(image,
sx, sy, sw, sh,
x, y, w, h);
return 1;
}
-};
+}
-module.exports = renderer;
\ No newline at end of file
diff --git a/cocos2d/core/renderer/canvas/renderers/sprite/sliced.js b/cocos2d/core/renderer/canvas/renderers/sprite/sliced.js
index f4c766f5bf5..84cd7c91dcb 100644
--- a/cocos2d/core/renderer/canvas/renderers/sprite/sliced.js
+++ b/cocos2d/core/renderer/canvas/renderers/sprite/sliced.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -23,24 +23,22 @@
THE SOFTWARE.
****************************************************************************/
+import Assembler from '../../../assembler';
+import RenderData from '../render-data';
+import CanvasSimpleSprite from './simple';
+
const utils = require('../utils');
-const simple = require('./simple');
-let renderer = {
- createData (sprite) {
- let renderData = sprite.requestRenderData();
- // 4 rows & cols
- renderData.dataLength = 4;
- return renderData;
- },
+export default class CanvasSlicedSprite extends CanvasSimpleSprite {
+ init () {
+ this._renderData = new RenderData();
+ this._renderData.dataLength = 4;
+ }
- updateRenderData: simple.updateRenderData,
-
updateUVs (sprite) {
let frame = sprite.spriteFrame;
- let renderData = sprite._renderData;
+ let renderData = this._renderData;
let rect = frame._rect;
- let texture = frame._texture;
// caculate texture coordinate
let leftWidth = frame.insetLeft;
@@ -51,39 +49,37 @@ let renderer = {
let centerHeight = rect.height - topHeight - bottomHeight;
// uv computation should take spritesheet into account.
- let data = renderData._data;
+ let verts = renderData.vertices;
if (frame._rotated) {
- data[0].u = rect.x;
- data[1].u = bottomHeight + rect.x;
- data[2].u = bottomHeight + centerHeight + rect.x;
- data[3].u = rect.x + rect.height;
- data[3].v = rect.y;
- data[2].v = leftWidth + rect.y;
- data[1].v = leftWidth + centerWidth + rect.y;
- data[0].v = rect.y + rect.width;
+ verts[0].u = rect.x;
+ verts[1].u = bottomHeight + rect.x;
+ verts[2].u = bottomHeight + centerHeight + rect.x;
+ verts[3].u = rect.x + rect.height;
+ verts[3].v = rect.y;
+ verts[2].v = leftWidth + rect.y;
+ verts[1].v = leftWidth + centerWidth + rect.y;
+ verts[0].v = rect.y + rect.width;
}
else {
- data[0].u = rect.x;
- data[1].u = leftWidth + rect.x;
- data[2].u = leftWidth + centerWidth + rect.x;
- data[3].u = rect.x + rect.width;
- data[3].v = rect.y;
- data[2].v = topHeight + rect.y;
- data[1].v = topHeight + centerHeight + rect.y;
- data[0].v = rect.y + rect.height;
+ verts[0].u = rect.x;
+ verts[1].u = leftWidth + rect.x;
+ verts[2].u = leftWidth + centerWidth + rect.x;
+ verts[3].u = rect.x + rect.width;
+ verts[3].v = rect.y;
+ verts[2].v = topHeight + rect.y;
+ verts[1].v = topHeight + centerHeight + rect.y;
+ verts[0].v = rect.y + rect.height;
}
- renderData.uvDirty = false;
- },
+ }
updateVerts (sprite) {
- let renderData = sprite._renderData,
- data = renderData._data,
+ let renderData = this._renderData,
+ verts = renderData.vertices,
node = sprite.node,
width = node.width, height = node.height,
appx = node.anchorX * width, appy = node.anchorY * height;
let frame = sprite.spriteFrame;
- let rect = frame._rect;
let leftWidth = frame.insetLeft;
let rightWidth = frame.insetRight;
let topHeight = frame.insetTop;
@@ -98,34 +94,49 @@ let renderer = {
sizableWidth = sizableWidth < 0 ? 0 : sizableWidth;
sizableHeight = sizableHeight < 0 ? 0 : sizableHeight;
- data[0].x = -appx;
- data[0].y = -appy;
- data[1].x = leftWidth * xScale - appx;
- data[1].y = bottomHeight * yScale - appy;
- data[2].x = data[1].x + sizableWidth;
- data[2].y = data[1].y + sizableHeight;
- data[3].x = width - appx;
- data[3].y = height - appy;
-
- renderData.vertDirty = false;
- },
+ if (frame._rotated) {
+ verts[0].y = -appx;
+ verts[0].x = -appy;
+ verts[1].y = rightWidth * xScale - appx;
+ verts[1].x = bottomHeight * yScale - appy;
+ verts[2].y = verts[1].y + sizableWidth;
+ verts[2].x = verts[1].x + sizableHeight;
+ verts[3].y = width - appx;
+ verts[3].x = height - appy;
+ } else {
+ verts[0].x = -appx;
+ verts[0].y = -appy;
+ verts[1].x = leftWidth * xScale - appx;
+ verts[1].y = bottomHeight * yScale - appy;
+ verts[2].x = verts[1].x + sizableWidth;
+ verts[2].y = verts[1].y + sizableHeight;
+ verts[3].x = width - appx;
+ verts[3].y = height - appy;
+ }
+
+ sprite._vertsDirty = false;
+ }
draw (ctx, comp) {
let node = comp.node;
+ let frame = comp._spriteFrame;
// Transform
let matrix = node._worldMatrix;
- let a = matrix.m00, b = matrix.m01, c = matrix.m04, d = matrix.m05,
- tx = matrix.m12, ty = matrix.m13;
+ let matrixm = matrix.m;
+ let a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
+ tx = matrixm[12], ty = matrixm[13];
ctx.transform(a, b, c, d, tx, ty);
ctx.scale(1, -1);
-
+ if (frame._rotated) {
+ ctx.rotate(- Math.PI / 2);
+ }
// TODO: handle blend function
// opacity
- ctx.globalAlpha = node.opacity / 255;
+ utils.context.setGlobalAlpha(ctx, node.opacity / 255);
- let tex = comp._spriteFrame._texture,
- data = comp._renderData._data;
+ let tex = frame._texture,
+ verts = this._renderData.vertices;
let image = utils.getColorizedImage(tex, node._color);
@@ -134,11 +145,11 @@ let renderer = {
x, y, w, h,
sx, sy, sw, sh;
for (let r = 0; r < 3; ++r) {
- bd = data[r];
- td = data[r+1];
+ bd = verts[r];
+ td = verts[r+1];
for (let c = 0; c < 3; ++c) {
- ld = data[c];
- rd = data[c+1];
+ ld = verts[c];
+ rd = verts[c+1];
x = ld.x;
y = bd.y;
w = rd.x - x;
@@ -161,6 +172,4 @@ let renderer = {
}
return drawCall;
}
-};
-
-module.exports = renderer;
\ No newline at end of file
+}
diff --git a/cocos2d/core/renderer/canvas/renderers/sprite/tiled.js b/cocos2d/core/renderer/canvas/renderers/sprite/tiled.js
index 20c9d9e62a7..e8438227fab 100644
--- a/cocos2d/core/renderer/canvas/renderers/sprite/tiled.js
+++ b/cocos2d/core/renderer/canvas/renderers/sprite/tiled.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -23,34 +23,25 @@
THE SOFTWARE.
****************************************************************************/
-const utils = require('../utils');
-const simple = require('./simple');
+import Assembler from '../../../assembler';
-let renderer = {
- createData (sprite) {
- let renderData = sprite.requestRenderData();
- return renderData;
- },
-
- updateRenderData (sprite) {
- if (!sprite._material) {
- sprite._activateMaterial();
- }
- },
+const utils = require('../utils');
+export default class CanvasTiledSprite extends Assembler {
draw (ctx, sprite) {
let node = sprite.node;
// Transform
let matrix = node._worldMatrix;
- let a = matrix.m00, b = matrix.m01, c = matrix.m04, d = matrix.m05,
- tx = matrix.m12, ty = matrix.m13;
+ let matrixm = matrix.m;
+ let a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
+ tx = matrixm[12], ty = matrixm[13];
ctx.transform(a, b, c, d, tx, ty);
ctx.scale(1, -1);
// TODO: handle blend function
// opacity
- ctx.globalAlpha = node.opacity / 255;
+ utils.context.setGlobalAlpha(ctx, node.opacity / 255);
let frame = sprite.spriteFrame;
let rect = frame._rect;
@@ -74,5 +65,3 @@ let renderer = {
return 1;
}
}
-
-module.exports = renderer
\ No newline at end of file
diff --git a/cocos2d/core/renderer/canvas/renderers/utils.js b/cocos2d/core/renderer/canvas/renderers/utils.js
index e42558ce5cb..0ac6d190331 100644
--- a/cocos2d/core/renderer/canvas/renderers/utils.js
+++ b/cocos2d/core/renderer/canvas/renderers/utils.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -27,9 +27,6 @@ const WHITE = (255<<16) + (255<<8) + 255;
const MAX_CANVAS_COUNT = 32;
function colorizedFrame (canvas, texture, color, sx, sy, sw, sh) {
- if (cc.sys.browserType === cc.sys.BROWSER_TYPE_WECHAT_GAME_SUB) {
- return canvas;
- }
let image = texture._image;
let ctx = canvas.getContext("2d");
@@ -119,7 +116,7 @@ module.exports = {
}
// get from cache
- let key = texture.url + cval;
+ let key = texture.nativeUrl + cval;
let cache = canvasMgr.getCanvas(key);
if (!cache) {
cache = canvasMgr.canvasPool.pop() || document.createElement("canvas");
@@ -130,11 +127,11 @@ module.exports = {
},
getFrameCache (texture, color, sx, sy, sw, sh) {
- if (!texture || !texture.url || sx < 0 || sy < 0 || sw <= 0 || sh <= 0) {
+ if (!texture || !texture.nativeUrl || sx < 0 || sy < 0 || sw <= 0 || sh <= 0) {
return null;
}
- let key = texture.url;
+ let key = texture.nativeUrl;
let generate = false;
let cval = color._val & 0x00ffffff;
if (cval !== WHITE) {
@@ -160,7 +157,27 @@ module.exports = {
},
dropColorizedImage (texture, color) {
- let key = texture.url + (color._val & 0x00ffffff);
+ let key = texture.nativeUrl + (color._val & 0x00ffffff);
canvasMgr.dropImage(key);
}
-};
\ No newline at end of file
+};
+
+// cache context data of device.
+let _globalAlpha = -1;
+
+let context = {
+ setGlobalAlpha (ctx, alpha) {
+ if (_globalAlpha === alpha) {
+ return
+ }
+
+ _globalAlpha = alpha;
+ ctx.globalAlpha = _globalAlpha;
+ },
+
+ reset () {
+ _globalAlpha = -1;
+ }
+}
+
+module.exports.context = context;
\ No newline at end of file
diff --git a/cocos2d/core/renderer/index.js b/cocos2d/core/renderer/index.js
index f0007f21dc8..56da4ef73a1 100644
--- a/cocos2d/core/renderer/index.js
+++ b/cocos2d/core/renderer/index.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -22,27 +22,28 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
+import gfx from '../../renderer/gfx';
-const renderEngine = require('./render-engine');
-const math = renderEngine.math;
+import InputAssembler from '../../renderer/core/input-assembler';
+import Pass from '../../renderer/core/pass';
-let _pos = math.vec3.create();
+// const RenderFlow = require('./render-flow');
function _initBuiltins(device) {
- let defaultTexture = new renderEngine.Texture2D(device, {
+ let defaultTexture = new gfx.Texture2D(device, {
images: [],
width: 128,
height: 128,
- wrapS: renderEngine.gfx.WRAP_REPEAT,
- wrapT: renderEngine.gfx.WRAP_REPEAT,
- format: renderEngine.gfx.TEXTURE_FMT_RGB8,
- mipmap: false,
+ wrapS: gfx.WRAP_REPEAT,
+ wrapT: gfx.WRAP_REPEAT,
+ format: gfx.TEXTURE_FMT_RGB8,
+ genMipmaps: false,
});
-
+
return {
defaultTexture: defaultTexture,
- programTemplates: renderEngine.shaders.templates,
- programChunks: renderEngine.shaders.chunks,
+ programTemplates: [],
+ programChunks: {},
};
}
@@ -57,7 +58,12 @@ function _initBuiltins(device) {
* @class renderer
* @static
*/
-cc.renderer = module.exports = {
+export default cc.renderer = {
+ Texture2D: null,
+
+ InputAssembler: InputAssembler,
+ Pass: Pass,
+
/**
* !#en The render engine is available only after cc.game.EVENT_ENGINE_INITED event.
* Normally it will be inited as the webgl render engine, but in wechat open context domain,
@@ -65,10 +71,10 @@ cc.renderer = module.exports = {
* !#zh 基础渲染引擎对象只在 cc.game.EVENT_ENGINE_INITED 事件触发后才可获取。
* 大多数情况下,它都会是 WebGL 渲染引擎实例,但是在微信开放数据域当中,它会是 Canvas 渲染引擎实例。请注意,从 2.0 开始,我们在其他平台和环境下都废弃了 Canvas 渲染器。
* @property renderEngine
+ * @deprecated
* @type {Object}
*/
- renderEngine: renderEngine,
- Texture2D: null,
+ renderEngine: null,
/*
* !#en The canvas object which provides the rendering context
@@ -81,7 +87,7 @@ cc.renderer = module.exports = {
* !#en The device object which provides device related rendering functionality, it divers for different render engine type.
* !#zh 提供设备渲染能力的对象,它对于不同的渲染环境功能也不相同。
* @property device
- * @type {renderer.renderEngine.Device}
+ * @type {renderer.Device}
*/
device: null,
scene: null,
@@ -92,82 +98,68 @@ cc.renderer = module.exports = {
* @type {Number}
*/
drawCalls: 0,
- _walker: null,
+ // Render component handler
+ _handle: null,
_cameraNode: null,
_camera: null,
_forward: null,
+ _flow: null,
initWebGL (canvas, opts) {
require('./webgl/assemblers');
- const RenderComponentWalker = require('./webgl/render-component-walker');
-
- this.Texture2D = renderEngine.Texture2D;
+ const ModelBatcher = require('./webgl/model-batcher');
+ this.Texture2D = gfx.Texture2D;
this.canvas = canvas;
+ this._flow = cc.RenderFlow;
+
if (CC_JSB && CC_NATIVERENDERER) {
// native codes will create an instance of Device, so just use the global instance.
- this.device = window.device;
+ this.device = gfx.Device.getInstance();
+ this.scene = new renderer.Scene();
+ let builtins = _initBuiltins(this.device);
+ this._forward = new renderer.ForwardRenderer(this.device, builtins);
+ let nativeFlow = new renderer.RenderFlow(this.device, this.scene, this._forward);
+ this._flow.init(nativeFlow);
}
else {
- this.device = new renderEngine.Device(canvas, opts);
+ let Scene = require('../../renderer/scene/scene');
+ let ForwardRenderer = require('../../renderer/renderers/forward-renderer');
+ this.device = new gfx.Device(canvas, opts);
+ this.scene = new Scene();
+ let builtins = _initBuiltins(this.device);
+ this._forward = new ForwardRenderer(this.device, builtins);
+ this._handle = new ModelBatcher(this.device, this.scene);
+ this._flow.init(this._handle, this._forward);
}
-
- this.scene = new renderEngine.Scene();
-
- this._walker = new RenderComponentWalker(this.device, this.scene);
-
- if (CC_EDITOR) {
- this._cameraNode = new cc.Node();
-
- this._camera = new renderEngine.Camera();
- this._camera.setColor(0, 0, 0, 1);
- this._camera.setFov(Math.PI * 60 / 180);
- this._camera.setNear(0.1);
- this._camera.setFar(1024);
- this._camera.setNode(this._cameraNode);
-
- let view = new renderEngine.View();
- this._camera.view = view;
- this._camera.dirty = true;
-
- if (CC_EDITOR) {
- this._camera.setColor(0, 0, 0, 0);
- }
- this._camera.setStages([
- 'transparent'
- ]);
- this.scene.addCamera(this._camera);
- }
-
- let builtins = _initBuiltins(this.device);
- this._forward = new renderEngine.ForwardRenderer(this.device, builtins);
},
initCanvas (canvas) {
- let canvasRenderer = require('./canvas');
+ const canvasRenderer = require('./canvas');
+ const Texture2D = require('./canvas/Texture2D');
+ const Device = require('./canvas/Device');
- if (CC_TEST) {
- // It's actually running with original render engine
- renderEngine.Texture2D = renderEngine.canvas.Texture2D;
- renderEngine.Device = renderEngine.canvas.Device;
- }
-
- this.Texture2D = renderEngine.Texture2D;
+ // It's actually running with original render engine
+ this.Device = Device;
+
+ this.Texture2D = Texture2D;
this.canvas = canvas;
- this.device = new renderEngine.Device(canvas);
+ this.device = new Device(canvas);
this._camera = {
a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0
};
- this._walker = new canvasRenderer.RenderComponentWalker(this.device, this._camera);
+ this._handle = new canvasRenderer.RenderComponentHandle(this.device, this._camera);
this._forward = new canvasRenderer.ForwardRenderer();
+ this._flow = cc.RenderFlow;
+ this._flow.init(this._handle, this._forward);
},
updateCameraViewport () {
// TODO: remove HACK
if (!CC_EDITOR && cc.director) {
let ecScene = cc.director.getScene();
- ecScene.setScale(1, 1, 1);
+ if (ecScene) ecScene.setScale(1, 1, 1);
}
if (cc.game.renderType === cc.game.RENDER_TYPE_CANVAS) {
@@ -178,35 +170,19 @@ cc.renderer = module.exports = {
this._camera.tx = vp.x;
this._camera.ty = vp.y + vp.height;
}
- else if (CC_EDITOR && this.canvas) {
- let canvas = this.canvas;
- let scaleX = cc.view.getScaleX();
- let scaleY = cc.view.getScaleY();
-
- let node = this._cameraNode;
- _pos.x = node.x = canvas.width / scaleX / 2;
- _pos.y = node.y = canvas.height / scaleY / 2;
- _pos.z = 0;
-
- node.z = canvas.height / scaleY / 1.1566;
- node.lookAt(_pos);
- this._camera.dirty = true;
- }
},
- render (ecScene) {
- this.device._stats.drawcalls = 0;
+ render (ecScene, dt) {
+ this.device.resetDrawCalls();
if (ecScene) {
// walk entity component scene to generate models
- this._walker.visit(ecScene);
- // Render models in renderer scene
- this._forward.render(this.scene);
- this.drawCalls = this.device._stats.drawcalls;
+ this._flow.render(ecScene, dt);
+ this.drawCalls = this.device.getDrawCalls();
}
},
clear () {
- this._walker.reset();
- this._forward._reset();
+ this._handle.reset();
+ this._forward.clear();
}
-};
\ No newline at end of file
+};
diff --git a/cocos2d/core/renderer/render-engine.canvas.js b/cocos2d/core/renderer/render-engine.canvas.js
deleted file mode 100644
index e13bca3552f..00000000000
--- a/cocos2d/core/renderer/render-engine.canvas.js
+++ /dev/null
@@ -1,8835 +0,0 @@
-
-/****************************************************************************
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- render-engine v1.2.0
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-
-'use strict';
-
-// reference: https://github.com/mziccard/node-timsort
-
-/**
- * Default minimum size of a run.
- */
-var DEFAULT_MIN_MERGE = 32;
-
-/**
- * Minimum ordered subsequece required to do galloping.
- */
-var DEFAULT_MIN_GALLOPING = 7;
-
-/**
- * Default tmp storage length. Can increase depending on the size of the
- * smallest run to merge.
- */
-var DEFAULT_TMP_STORAGE_LENGTH = 256;
-
-/**
- * Pre-computed powers of 10 for efficient lexicographic comparison of
- * small integers.
- */
-var POWERS_OF_TEN = [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9];
-
-/**
- * Estimate the logarithm base 10 of a small integer.
- *
- * @param {number} x - The integer to estimate the logarithm of.
- * @return {number} - The estimated logarithm of the integer.
- */
-function log10(x) {
- if (x < 1e5) {
- if (x < 1e2) {
- return x < 1e1 ? 0 : 1;
- }
-
- if (x < 1e4) {
- return x < 1e3 ? 2 : 3;
- }
-
- return 4;
- }
-
- if (x < 1e7) {
- return x < 1e6 ? 5 : 6;
- }
-
- if (x < 1e9) {
- return x < 1e8 ? 7 : 8;
- }
-
- return 9;
-}
-
-/**
- * Default alphabetical comparison of items.
- *
- * @param {string|object|number} a - First element to compare.
- * @param {string|object|number} b - Second element to compare.
- * @return {number} - A positive number if a.toString() > b.toString(), a
- * negative number if .toString() < b.toString(), 0 otherwise.
- */
-function alphabeticalCompare(a, b) {
- if (a === b) {
- return 0;
- }
-
- if (~~a === a && ~~b === b) {
- if (a === 0 || b === 0) {
- return a < b ? -1 : 1;
- }
-
- if (a < 0 || b < 0) {
- if (b >= 0) {
- return -1;
- }
-
- if (a >= 0) {
- return 1;
- }
-
- a = -a;
- b = -b;
- }
-
- var al = log10(a);
- var bl = log10(b);
-
- var t = 0;
-
- if (al < bl) {
- a *= POWERS_OF_TEN[bl - al - 1];
- b /= 10;
- t = -1;
- } else if (al > bl) {
- b *= POWERS_OF_TEN[al - bl - 1];
- a /= 10;
- t = 1;
- }
-
- if (a === b) {
- return t;
- }
-
- return a < b ? -1 : 1;
- }
-
- var aStr = String(a);
- var bStr = String(b);
-
- if (aStr === bStr) {
- return 0;
- }
-
- return aStr < bStr ? -1 : 1;
-}
-
-/**
- * Compute minimum run length for TimSort
- *
- * @param {number} n - The size of the array to sort.
- */
-function minRunLength(n) {
- var r = 0;
-
- while (n >= DEFAULT_MIN_MERGE) {
- r |= (n & 1);
- n >>= 1;
- }
-
- return n + r;
-}
-
-/**
- * Counts the length of a monotonically ascending or strictly monotonically
- * descending sequence (run) starting at array[lo] in the range [lo, hi). If
- * the run is descending it is made ascending.
- *
- * @param {array} array - The array to reverse.
- * @param {number} lo - First element in the range (inclusive).
- * @param {number} hi - Last element in the range.
- * @param {function} compare - Item comparison function.
- * @return {number} - The length of the run.
- */
-function makeAscendingRun(array, lo, hi, compare) {
- var runHi = lo + 1;
-
- if (runHi === hi) {
- return 1;
- }
-
- // Descending
- if (compare(array[runHi++], array[lo]) < 0) {
- while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) {
- runHi++;
- }
-
- reverseRun(array, lo, runHi);
- // Ascending
- } else {
- while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) {
- runHi++;
- }
- }
-
- return runHi - lo;
-}
-
-/**
- * Reverse an array in the range [lo, hi).
- *
- * @param {array} array - The array to reverse.
- * @param {number} lo - First element in the range (inclusive).
- * @param {number} hi - Last element in the range.
- */
-function reverseRun(array, lo, hi) {
- hi--;
-
- while (lo < hi) {
- var t = array[lo];
- array[lo++] = array[hi];
- array[hi--] = t;
- }
-}
-
-/**
- * Perform the binary sort of the array in the range [lo, hi) where start is
- * the first element possibly out of order.
- *
- * @param {array} array - The array to sort.
- * @param {number} lo - First element in the range (inclusive).
- * @param {number} hi - Last element in the range.
- * @param {number} start - First element possibly out of order.
- * @param {function} compare - Item comparison function.
- */
-function binaryInsertionSort(array, lo, hi, start, compare) {
- if (start === lo) {
- start++;
- }
-
- for (; start < hi; start++) {
- var pivot = array[start];
-
- // Ranges of the array where pivot belongs
- var left = lo;
- var right = start;
-
- /*
- * pivot >= array[i] for i in [lo, left)
- * pivot < array[i] for i in in [right, start)
- */
- while (left < right) {
- var mid = (left + right) >>> 1;
-
- if (compare(pivot, array[mid]) < 0) {
- right = mid;
- } else {
- left = mid + 1;
- }
- }
-
- /*
- * Move elements right to make room for the pivot. If there are elements
- * equal to pivot, left points to the first slot after them: this is also
- * a reason for which TimSort is stable
- */
- var n = start - left;
- // Switch is just an optimization for small arrays
- switch (n) {
- case 3:
- array[left + 3] = array[left + 2];
- /* falls through */
- case 2:
- array[left + 2] = array[left + 1];
- /* falls through */
- case 1:
- array[left + 1] = array[left];
- break;
- default:
- while (n > 0) {
- array[left + n] = array[left + n - 1];
- n--;
- }
- }
-
- array[left] = pivot;
- }
-}
-
-/**
- * Find the position at which to insert a value in a sorted range. If the range
- * contains elements equal to the value the leftmost element index is returned
- * (for stability).
- *
- * @param {number} value - Value to insert.
- * @param {array} array - The array in which to insert value.
- * @param {number} start - First element in the range.
- * @param {number} length - Length of the range.
- * @param {number} hint - The index at which to begin the search.
- * @param {function} compare - Item comparison function.
- * @return {number} - The index where to insert value.
- */
-function gallopLeft(value, array, start, length, hint, compare) {
- var lastOffset = 0;
- var maxOffset = 0;
- var offset = 1;
-
- if (compare(value, array[start + hint]) > 0) {
- maxOffset = length - hint;
-
- while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) {
- lastOffset = offset;
- offset = (offset << 1) + 1;
-
- if (offset <= 0) {
- offset = maxOffset;
- }
- }
-
- if (offset > maxOffset) {
- offset = maxOffset;
- }
-
- // Make offsets relative to start
- lastOffset += hint;
- offset += hint;
-
- // value <= array[start + hint]
- } else {
- maxOffset = hint + 1;
- while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) {
- lastOffset = offset;
- offset = (offset << 1) + 1;
-
- if (offset <= 0) {
- offset = maxOffset;
- }
- }
- if (offset > maxOffset) {
- offset = maxOffset;
- }
-
- // Make offsets relative to start
- var tmp = lastOffset;
- lastOffset = hint - offset;
- offset = hint - tmp;
- }
-
- /*
- * Now array[start+lastOffset] < value <= array[start+offset], so value
- * belongs somewhere in the range (start + lastOffset, start + offset]. Do a
- * binary search, with invariant array[start + lastOffset - 1] < value <=
- * array[start + offset].
- */
- lastOffset++;
- while (lastOffset < offset) {
- var m = lastOffset + ((offset - lastOffset) >>> 1);
-
- if (compare(value, array[start + m]) > 0) {
- lastOffset = m + 1;
-
- } else {
- offset = m;
- }
- }
- return offset;
-}
-
-/**
- * Find the position at which to insert a value in a sorted range. If the range
- * contains elements equal to the value the rightmost element index is returned
- * (for stability).
- *
- * @param {number} value - Value to insert.
- * @param {array} array - The array in which to insert value.
- * @param {number} start - First element in the range.
- * @param {number} length - Length of the range.
- * @param {number} hint - The index at which to begin the search.
- * @param {function} compare - Item comparison function.
- * @return {number} - The index where to insert value.
- */
-function gallopRight(value, array, start, length, hint, compare) {
- var lastOffset = 0;
- var maxOffset = 0;
- var offset = 1;
-
- if (compare(value, array[start + hint]) < 0) {
- maxOffset = hint + 1;
-
- while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) {
- lastOffset = offset;
- offset = (offset << 1) + 1;
-
- if (offset <= 0) {
- offset = maxOffset;
- }
- }
-
- if (offset > maxOffset) {
- offset = maxOffset;
- }
-
- // Make offsets relative to start
- var tmp = lastOffset;
- lastOffset = hint - offset;
- offset = hint - tmp;
-
- // value >= array[start + hint]
- } else {
- maxOffset = length - hint;
-
- while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) {
- lastOffset = offset;
- offset = (offset << 1) + 1;
-
- if (offset <= 0) {
- offset = maxOffset;
- }
- }
-
- if (offset > maxOffset) {
- offset = maxOffset;
- }
-
- // Make offsets relative to start
- lastOffset += hint;
- offset += hint;
- }
-
- /*
- * Now array[start+lastOffset] < value <= array[start+offset], so value
- * belongs somewhere in the range (start + lastOffset, start + offset]. Do a
- * binary search, with invariant array[start + lastOffset - 1] < value <=
- * array[start + offset].
- */
- lastOffset++;
-
- while (lastOffset < offset) {
- var m = lastOffset + ((offset - lastOffset) >>> 1);
-
- if (compare(value, array[start + m]) < 0) {
- offset = m;
-
- } else {
- lastOffset = m + 1;
- }
- }
-
- return offset;
-}
-
-var TimSort = function TimSort(array, compare) {
- this.array = array;
- this.compare = compare;
- this.minGallop = DEFAULT_MIN_GALLOPING;
- this.length = array.length;
-
- this.tmpStorageLength = DEFAULT_TMP_STORAGE_LENGTH;
- if (this.length < 2 * DEFAULT_TMP_STORAGE_LENGTH) {
- this.tmpStorageLength = this.length >>> 1;
- }
-
- this.tmp = new Array(this.tmpStorageLength);
-
- this.stackLength =
- (this.length < 120 ? 5 :
- this.length < 1542 ? 10 :
- this.length < 119151 ? 19 : 40);
-
- this.runStart = new Array(this.stackLength);
- this.runLength = new Array(this.stackLength);
- this.stackSize = 0;
-};
-
-/**
- * Push a new run on TimSort's stack.
- *
- * @param {number} runStart - Start index of the run in the original array.
- * @param {number} runLength - Length of the run;
- */
-TimSort.prototype.pushRun = function pushRun (runStart, runLength) {
- this.runStart[this.stackSize] = runStart;
- this.runLength[this.stackSize] = runLength;
- this.stackSize += 1;
-};
-
-/**
- * Merge runs on TimSort's stack so that the following holds for all i:
- * 1) runLength[i - 3] > runLength[i - 2] + runLength[i - 1]
- * 2) runLength[i - 2] > runLength[i - 1]
- */
-TimSort.prototype.mergeRuns = function mergeRuns () {
- var this$1 = this;
-
- while (this.stackSize > 1) {
- var n = this$1.stackSize - 2;
-
- if ((n >= 1 &&
- this$1.runLength[n - 1] <= this$1.runLength[n] + this$1.runLength[n + 1]) ||
- (n >= 2 &&
- this$1.runLength[n - 2] <= this$1.runLength[n] + this$1.runLength[n - 1])) {
-
- if (this$1.runLength[n - 1] < this$1.runLength[n + 1]) {
- n--;
- }
-
- } else if (this$1.runLength[n] > this$1.runLength[n + 1]) {
- break;
- }
- this$1.mergeAt(n);
- }
-};
-
-/**
- * Merge all runs on TimSort's stack until only one remains.
- */
-TimSort.prototype.forceMergeRuns = function forceMergeRuns () {
- var this$1 = this;
-
- while (this.stackSize > 1) {
- var n = this$1.stackSize - 2;
-
- if (n > 0 && this$1.runLength[n - 1] < this$1.runLength[n + 1]) {
- n--;
- }
-
- this$1.mergeAt(n);
- }
-};
-
-/**
- * Merge the runs on the stack at positions i and i+1. Must be always be called
- * with i=stackSize-2 or i=stackSize-3 (that is, we merge on top of the stack).
- *
- * @param {number} i - Index of the run to merge in TimSort's stack.
- */
-TimSort.prototype.mergeAt = function mergeAt (i) {
- var compare = this.compare;
- var array = this.array;
-
- var start1 = this.runStart[i];
- var length1 = this.runLength[i];
- var start2 = this.runStart[i + 1];
- var length2 = this.runLength[i + 1];
-
- this.runLength[i] = length1 + length2;
-
- if (i === this.stackSize - 3) {
- this.runStart[i + 1] = this.runStart[i + 2];
- this.runLength[i + 1] = this.runLength[i + 2];
- }
-
- this.stackSize--;
-
- /*
- * Find where the first element in the second run goes in run1. Previous
- * elements in run1 are already in place
- */
- var k = gallopRight(array[start2], array, start1, length1, 0, compare);
- start1 += k;
- length1 -= k;
-
- if (length1 === 0) {
- return;
- }
-
- /*
- * Find where the last element in the first run goes in run2. Next elements
- * in run2 are already in place
- */
- length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare);
-
- if (length2 === 0) {
- return;
- }
-
- /*
- * Merge remaining runs. A tmp array with length = min(length1, length2) is
- * used
- */
- if (length1 <= length2) {
- this.mergeLow(start1, length1, start2, length2);
-
- } else {
- this.mergeHigh(start1, length1, start2, length2);
- }
-};
-
-/**
- * Merge two adjacent runs in a stable way. The runs must be such that the
- * first element of run1 is bigger than the first element in run2 and the
- * last element of run1 is greater than all the elements in run2.
- * The method should be called when run1.length <= run2.length as it uses
- * TimSort temporary array to store run1. Use mergeHigh if run1.length >
- * run2.length.
- *
- * @param {number} start1 - First element in run1.
- * @param {number} length1 - Length of run1.
- * @param {number} start2 - First element in run2.
- * @param {number} length2 - Length of run2.
- */
-TimSort.prototype.mergeLow = function mergeLow (start1, length1, start2, length2) {
-
- var compare = this.compare;
- var array = this.array;
- var tmp = this.tmp;
- var i = 0;
-
- for (i = 0; i < length1; i++) {
- tmp[i] = array[start1 + i];
- }
-
- var cursor1 = 0;
- var cursor2 = start2;
- var dest = start1;
-
- array[dest++] = array[cursor2++];
-
- if (--length2 === 0) {
- for (i = 0; i < length1; i++) {
- array[dest + i] = tmp[cursor1 + i];
- }
- return;
- }
-
- if (length1 === 1) {
- for (i = 0; i < length2; i++) {
- array[dest + i] = array[cursor2 + i];
- }
- array[dest + length2] = tmp[cursor1];
- return;
- }
-
- var minGallop = this.minGallop;
-
- while (true) {
- var count1 = 0;
- var count2 = 0;
- var exit = false;
-
- do {
- if (compare(array[cursor2], tmp[cursor1]) < 0) {
- array[dest++] = array[cursor2++];
- count2++;
- count1 = 0;
-
- if (--length2 === 0) {
- exit = true;
- break;
- }
-
- } else {
- array[dest++] = tmp[cursor1++];
- count1++;
- count2 = 0;
- if (--length1 === 1) {
- exit = true;
- break;
- }
- }
- } while ((count1 | count2) < minGallop);
-
- if (exit) {
- break;
- }
-
- do {
- count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare);
-
- if (count1 !== 0) {
- for (i = 0; i < count1; i++) {
- array[dest + i] = tmp[cursor1 + i];
- }
-
- dest += count1;
- cursor1 += count1;
- length1 -= count1;
- if (length1 <= 1) {
- exit = true;
- break;
- }
- }
-
- array[dest++] = array[cursor2++];
-
- if (--length2 === 0) {
- exit = true;
- break;
- }
-
- count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare);
-
- if (count2 !== 0) {
- for (i = 0; i < count2; i++) {
- array[dest + i] = array[cursor2 + i];
- }
-
- dest += count2;
- cursor2 += count2;
- length2 -= count2;
-
- if (length2 === 0) {
- exit = true;
- break;
- }
- }
- array[dest++] = tmp[cursor1++];
-
- if (--length1 === 1) {
- exit = true;
- break;
- }
-
- minGallop--;
-
- } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
-
- if (exit) {
- break;
- }
-
- if (minGallop < 0) {
- minGallop = 0;
- }
-
- minGallop += 2;
- }
-
- this.minGallop = minGallop;
-
- if (minGallop < 1) {
- this.minGallop = 1;
- }
-
- if (length1 === 1) {
- for (i = 0; i < length2; i++) {
- array[dest + i] = array[cursor2 + i];
- }
- array[dest + length2] = tmp[cursor1];
-
- } else if (length1 === 0) {
- throw new Error('mergeLow preconditions were not respected');
-
- } else {
- for (i = 0; i < length1; i++) {
- array[dest + i] = tmp[cursor1 + i];
- }
- }
-};
-
-/**
- * Merge two adjacent runs in a stable way. The runs must be such that the
- * first element of run1 is bigger than the first element in run2 and the
- * last element of run1 is greater than all the elements in run2.
- * The method should be called when run1.length > run2.length as it uses
- * TimSort temporary array to store run2. Use mergeLow if run1.length <=
- * run2.length.
- *
- * @param {number} start1 - First element in run1.
- * @param {number} length1 - Length of run1.
- * @param {number} start2 - First element in run2.
- * @param {number} length2 - Length of run2.
- */
-TimSort.prototype.mergeHigh = function mergeHigh (start1, length1, start2, length2) {
- var compare = this.compare;
- var array = this.array;
- var tmp = this.tmp;
- var i = 0;
-
- for (i = 0; i < length2; i++) {
- tmp[i] = array[start2 + i];
- }
-
- var cursor1 = start1 + length1 - 1;
- var cursor2 = length2 - 1;
- var dest = start2 + length2 - 1;
- var customCursor = 0;
- var customDest = 0;
-
- array[dest--] = array[cursor1--];
-
- if (--length1 === 0) {
- customCursor = dest - (length2 - 1);
-
- for (i = 0; i < length2; i++) {
- array[customCursor + i] = tmp[i];
- }
-
- return;
- }
-
- if (length2 === 1) {
- dest -= length1;
- cursor1 -= length1;
- customDest = dest + 1;
- customCursor = cursor1 + 1;
-
- for (i = length1 - 1; i >= 0; i--) {
- array[customDest + i] = array[customCursor + i];
- }
-
- array[dest] = tmp[cursor2];
- return;
- }
-
- var minGallop = this.minGallop;
-
- while (true) {
- var count1 = 0;
- var count2 = 0;
- var exit = false;
-
- do {
- if (compare(tmp[cursor2], array[cursor1]) < 0) {
- array[dest--] = array[cursor1--];
- count1++;
- count2 = 0;
- if (--length1 === 0) {
- exit = true;
- break;
- }
-
- } else {
- array[dest--] = tmp[cursor2--];
- count2++;
- count1 = 0;
- if (--length2 === 1) {
- exit = true;
- break;
- }
- }
-
- } while ((count1 | count2) < minGallop);
-
- if (exit) {
- break;
- }
-
- do {
- count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare);
-
- if (count1 !== 0) {
- dest -= count1;
- cursor1 -= count1;
- length1 -= count1;
- customDest = dest + 1;
- customCursor = cursor1 + 1;
-
- for (i = count1 - 1; i >= 0; i--) {
- array[customDest + i] = array[customCursor + i];
- }
-
- if (length1 === 0) {
- exit = true;
- break;
- }
- }
-
- array[dest--] = tmp[cursor2--];
-
- if (--length2 === 1) {
- exit = true;
- break;
- }
-
- count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare);
-
- if (count2 !== 0) {
- dest -= count2;
- cursor2 -= count2;
- length2 -= count2;
- customDest = dest + 1;
- customCursor = cursor2 + 1;
-
- for (i = 0; i < count2; i++) {
- array[customDest + i] = tmp[customCursor + i];
- }
-
- if (length2 <= 1) {
- exit = true;
- break;
- }
- }
-
- array[dest--] = array[cursor1--];
-
- if (--length1 === 0) {
- exit = true;
- break;
- }
-
- minGallop--;
-
- } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
-
- if (exit) {
- break;
- }
-
- if (minGallop < 0) {
- minGallop = 0;
- }
-
- minGallop += 2;
- }
-
- this.minGallop = minGallop;
-
- if (minGallop < 1) {
- this.minGallop = 1;
- }
-
- if (length2 === 1) {
- dest -= length1;
- cursor1 -= length1;
- customDest = dest + 1;
- customCursor = cursor1 + 1;
-
- for (i = length1 - 1; i >= 0; i--) {
- array[customDest + i] = array[customCursor + i];
- }
-
- array[dest] = tmp[cursor2];
-
- } else if (length2 === 0) {
- throw new Error('mergeHigh preconditions were not respected');
-
- } else {
- customCursor = dest - (length2 - 1);
- for (i = 0; i < length2; i++) {
- array[customCursor + i] = tmp[i];
- }
- }
-};
-
-/**
- * Sort an array in the range [lo, hi) using TimSort.
- *
- * @param {array} array - The array to sort.
- * @param {number} lo - First element in the range (inclusive).
- * @param {number} hi - Last element in the range.
- * @param {function=} compare - Item comparison function. Default is alphabetical.
- */
-function sort (array, lo, hi, compare) {
- if (!Array.isArray(array)) {
- throw new TypeError('Can only sort arrays');
- }
-
- /*
- * Handle the case where a comparison function is not provided. We do
- * lexicographic sorting
- */
-
- if (lo === undefined) {
- lo = 0;
- }
-
- if (hi === undefined) {
- hi = array.length;
- }
-
- if (compare === undefined) {
- compare = alphabeticalCompare;
- }
-
- var remaining = hi - lo;
-
- // The array is already sorted
- if (remaining < 2) {
- return;
- }
-
- var runLength = 0;
- // On small arrays binary sort can be used directly
- if (remaining < DEFAULT_MIN_MERGE) {
- runLength = makeAscendingRun(array, lo, hi, compare);
- binaryInsertionSort(array, lo, hi, lo + runLength, compare);
- return;
- }
-
- var ts = new TimSort(array, compare);
-
- var minRun = minRunLength(remaining);
-
- do {
- runLength = makeAscendingRun(array, lo, hi, compare);
- if (runLength < minRun) {
- var force = remaining;
- if (force > minRun) {
- force = minRun;
- }
-
- binaryInsertionSort(array, lo, lo + force, lo + runLength, compare);
- runLength = force;
- }
- // Push new run and merge if necessary
- ts.pushRun(lo, runLength);
- ts.mergeRuns();
-
- // Go find next run
- remaining -= runLength;
- lo += runLength;
-
- } while (remaining !== 0);
-
- // Force merging of remaining runs
- ts.forceMergeRuns();
-}
-
-var FixedArray = function FixedArray(size) {
- this._count = 0;
- this._data = new Array(size);
-};
-
-var prototypeAccessors = { length: { configurable: true },data: { configurable: true } };
-
-FixedArray.prototype._resize = function _resize (size) {
- var this$1 = this;
-
- if (size > this._data.length) {
- for (var i = this._data.length; i < size; ++i) {
- this$1._data[i] = undefined;
- }
- }
-};
-
-prototypeAccessors.length.get = function () {
- return this._count;
-};
-
-prototypeAccessors.data.get = function () {
- return this._data;
-};
-
-FixedArray.prototype.reset = function reset () {
- var this$1 = this;
-
- for (var i = 0; i < this._count; ++i) {
- this$1._data[i] = undefined;
- }
-
- this._count = 0;
-};
-
-FixedArray.prototype.push = function push (val) {
- if (this._count >= this._data.length) {
- this._resize(this._data.length * 2);
- }
-
- this._data[this._count] = val;
- ++this._count;
-};
-
-FixedArray.prototype.pop = function pop () {
- --this._count;
-
- if (this._count < 0) {
- this._count = 0;
- }
-
- var ret = this._data[this._count];
- this._data[this._count] = undefined;
-
- return ret;
-};
-
-FixedArray.prototype.fastRemove = function fastRemove (idx) {
- if (idx >= this._count) {
- return;
- }
-
- var last = this._count - 1;
- this._data[idx] = this._data[last];
- this._data[last] = undefined;
- this._count -= 1;
-};
-
-FixedArray.prototype.indexOf = function indexOf (val) {
- var idx = this._data.indexOf(val);
- if (idx >= this._count) {
- return -1;
- }
-
- return idx;
-};
-
-FixedArray.prototype.sort = function sort$1 (cmp) {
- return sort(this._data, 0, this._count, cmp);
-};
-
-Object.defineProperties( FixedArray.prototype, prototypeAccessors );
-
-var Pool = function Pool(fn, size) {
- var this$1 = this;
-
- this._fn = fn;
- this._idx = size - 1;
- this._frees = new Array(size);
-
- for (var i = 0; i < size; ++i) {
- this$1._frees[i] = fn();
- }
-};
-
-Pool.prototype._expand = function _expand (size) {
- var this$1 = this;
-
- var old = this._frees;
- this._frees = new Array(size);
-
- var len = size - old.length;
- for (var i = 0; i < len; ++i) {
- this$1._frees[i] = this$1._fn();
- }
-
- for (var i$1 = len, j = 0; i$1 < size; ++i$1, ++j) {
- this$1._frees[i$1] = old[j];
- }
-
- this._idx += len;
-};
-
-Pool.prototype.alloc = function alloc () {
- // create some more space (expand by 20%, minimum 1)
- if (this._idx < 0) {
- this._expand(Math.round(this._frees.length * 1.2) + 1);
- }
-
- var ret = this._frees[this._idx];
- this._frees[this._idx] = null;
- --this._idx;
-
- return ret;
-};
-
-Pool.prototype.free = function free (obj) {
- ++this._idx;
- this._frees[this._idx] = obj;
-};
-
-// NOTE: you must have `_prev` and `_next` field in the object returns by `fn`
-
-var LinkedArray = function LinkedArray(fn, size) {
- this._fn = fn;
- this._count = 0;
- this._head = null;
- this._tail = null;
-
- this._pool = new Pool(fn, size);
-};
-
-var prototypeAccessors$1 = { head: { configurable: true },tail: { configurable: true },length: { configurable: true } };
-
-prototypeAccessors$1.head.get = function () {
- return this._head;
-};
-
-prototypeAccessors$1.tail.get = function () {
- return this._tail;
-};
-
-prototypeAccessors$1.length.get = function () {
- return this._count;
-};
-
-LinkedArray.prototype.add = function add () {
- var node = this._pool.alloc();
-
- if (!this._tail) {
- this._head = node;
- } else {
- this._tail._next = node;
- node._prev = this._tail;
- }
- this._tail = node;
- this._count += 1;
-
- return node;
-};
-
-LinkedArray.prototype.remove = function remove (node) {
- if (node._prev) {
- node._prev._next = node._next;
- } else {
- this._head = node._next;
- }
-
- if (node._next) {
- node._next._prev = node._prev;
- } else {
- this._tail = node._prev;
- }
-
- node._next = null;
- node._prev = null;
- this._pool.free(node);
- this._count -= 1;
-};
-
-LinkedArray.prototype.forEach = function forEach (fn, binder) {
- var this$1 = this;
-
- var cursor = this._head;
- if (!cursor) {
- return;
- }
-
- if (binder) {
- fn = fn.bind(binder);
- }
-
- var idx = 0;
- var next = cursor;
-
- while (cursor) {
- next = cursor._next;
- fn(cursor, idx, this$1);
-
- cursor = next;
- ++idx;
- }
-};
-
-Object.defineProperties( LinkedArray.prototype, prototypeAccessors$1 );
-
-var RecyclePool = function RecyclePool(fn, size) {
- var this$1 = this;
-
- this._fn = fn;
- this._count = 0;
- this._data = new Array(size);
-
- for (var i = 0; i < size; ++i) {
- this$1._data[i] = fn();
- }
-};
-
-var prototypeAccessors$2 = { length: { configurable: true },data: { configurable: true } };
-
-prototypeAccessors$2.length.get = function () {
- return this._count;
-};
-
-prototypeAccessors$2.data.get = function () {
- return this._data;
-};
-
-RecyclePool.prototype.reset = function reset () {
- this._count = 0;
-};
-
-RecyclePool.prototype.resize = function resize (size) {
- var this$1 = this;
-
- if (size > this._data.length) {
- for (var i = this._data.length; i < size; ++i) {
- this$1._data[i] = this$1._fn();
- }
- }
-};
-
-RecyclePool.prototype.add = function add () {
- if (this._count >= this._data.length) {
- this.resize(this._data.length * 2);
- }
-
- return this._data[this._count++];
-};
-
-RecyclePool.prototype.remove = function remove (idx) {
- if (idx >= this._count) {
- return;
- }
-
- var last = this._count - 1;
- var tmp = this._data[idx];
- this._data[idx] = this._data[last];
- this._data[last] = tmp;
- this._count -= 1;
-};
-
-RecyclePool.prototype.sort = function sort$1 (cmp) {
- return sort(this._data, 0, this._count, cmp);
-};
-
-Object.defineProperties( RecyclePool.prototype, prototypeAccessors$2 );
-
-var _bufferPools = Array(8);
-for (var i = 0; i < 8; ++i) {
- _bufferPools[i] = [];
-}
-
-// Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
-
-/**
- * BaseRenderData is a core data abstraction for renderer, this is a abstract class.
- * An inherited render data type should define raw vertex datas.
- * User should also define the effect, vertex count and index count.
- */
-var BaseRenderData = function BaseRenderData () {
- this.material = null;
- this.vertexCount = 0;
- this.indiceCount = 0;
-};
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var _pool;
-var _dataPool = new Pool(function () {
- return {
- x: 0.0,
- y: 0.0,
- u: 0.0,
- v: 0.0,
- color: 0
- };
-}, 128);
-
-/**
- * RenderData is most widely used render data type.
- * It describes raw vertex data with a fixed data layout.
- * Each vertex is described by five property: x, y, u, v, color. The data layout might be extended in the future.
- * Vertex data objects are managed automatically by RenderData, user only need to set the dataLength property.
- * User can also define rendering index orders for the vertex list.
- */
-var RenderData = (function (BaseRenderData$$1) {
- function RenderData () {
- BaseRenderData$$1.call(this);
- this._data = [];
- this._indices = [];
-
- this._pivotX = 0;
- this._pivotY = 0;
- this._width = 0;
- this._height = 0;
-
- this.uvDirty = true;
- this.vertDirty = true;
- }
-
- if ( BaseRenderData$$1 ) RenderData.__proto__ = BaseRenderData$$1;
- RenderData.prototype = Object.create( BaseRenderData$$1 && BaseRenderData$$1.prototype );
- RenderData.prototype.constructor = RenderData;
-
- var prototypeAccessors = { type: { configurable: true },dataLength: { configurable: true } };
-
- prototypeAccessors.type.get = function () {
- return RenderData.type;
- };
-
- prototypeAccessors.dataLength.get = function () {
- return this._data.length;
- };
-
- prototypeAccessors.dataLength.set = function (length) {
- var data = this._data;
- if (data.length !== length) {
- // Free extra data
- for (var i = length; i < data.length; i++) {
- _dataPool.free(data[i]);
- }
- // Alloc needed data
- for (var i$1 = data.length; i$1 < length; i$1++) {
- data[i$1] = _dataPool.alloc();
- }
- data.length = length;
- }
- };
-
- RenderData.prototype.updateSizeNPivot = function updateSizeNPivot (width, height, pivotX, pivotY) {
- if (width !== this._width ||
- height !== this._height ||
- pivotX !== this._pivotX ||
- pivotY !== this._pivotY)
- {
- this._width = width;
- this._height = height;
- this._pivotX = pivotX;
- this._pivotY = pivotY;
- this.vertDirty = true;
- }
- };
-
- RenderData.alloc = function alloc () {
- return _pool.alloc();
- };
-
- RenderData.free = function free (data) {
- if (data instanceof RenderData) {
- for (var i = data.length-1; i > 0; i--) {
- _dataPool.free(data._data[i]);
- }
- data._data.length = 0;
- data._indices.length = 0;
- data.material = null;
- data.uvDirty = true;
- data.vertDirty = true;
- data.vertexCount = 0;
- data.indiceCount = 0;
- _pool.free(data);
- }
- };
-
- Object.defineProperties( RenderData.prototype, prototypeAccessors );
-
- return RenderData;
-}(BaseRenderData));
-
-RenderData.type = 'RenderData';
-
-_pool = new Pool(function () {
- return new RenderData();
-}, 32);
-
-var _d2r = Math.PI / 180.0;
-var _r2d = 180.0 / Math.PI;
-
-/**
- * @property {number} EPSILON
- */
-var EPSILON = 0.000001;
-
-/**
- * Tests whether or not the arguments have approximately the same value, within an absolute
- * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less
- * than or equal to 1.0, and a relative tolerance is used for larger values)
- *
- * @param {Number} a The first number to test.
- * @param {Number} b The second number to test.
- * @returns {Boolean} True if the numbers are approximately equal, false otherwise.
- */
-function equals(a, b) {
- return Math.abs(a - b) <= EPSILON * Math.max(1.0, Math.abs(a), Math.abs(b));
-}
-
-/**
- * Tests whether or not the arguments have approximately the same value by given maxDiff
- *
- * @param {Number} a The first number to test.
- * @param {Number} b The second number to test.
- * @param {Number} maxDiff Maximum difference.
- * @returns {Boolean} True if the numbers are approximately equal, false otherwise.
- */
-function approx(a, b, maxDiff) {
- maxDiff = maxDiff || EPSILON;
- return Math.abs(a - b) <= maxDiff;
-}
-
-/**
- * Clamps a value between a minimum float and maximum float value.
- *
- * @method clamp
- * @param {number} val
- * @param {number} min
- * @param {number} max
- * @return {number}
- */
-function clamp(val, min, max) {
- return val < min ? min : val > max ? max : val;
-}
-
-/**
- * Clamps a value between 0 and 1.
- *
- * @method clamp01
- * @param {number} val
- * @return {number}
- */
-function clamp01(val) {
- return val < 0 ? 0 : val > 1 ? 1 : val;
-}
-
-/**
- * @method lerp
- * @param {number} from
- * @param {number} to
- * @param {number} ratio - the interpolation coefficient
- * @return {number}
- */
-function lerp(from, to, ratio) {
- return from + (to - from) * ratio;
-}
-
-/**
-* Convert Degree To Radian
-*
-* @param {Number} a Angle in Degrees
-*/
-function toRadian(a) {
- return a * _d2r;
-}
-
-/**
-* Convert Radian To Degree
-*
-* @param {Number} a Angle in Radian
-*/
-function toDegree(a) {
- return a * _r2d;
-}
-
-/**
-* @method random
-*/
-var random = Math.random;
-
-/**
- * Returns a floating-point random number between min (inclusive) and max (exclusive).
- *
- * @method randomRange
- * @param {number} min
- * @param {number} max
- * @return {number} the random number
- */
-function randomRange(min, max) {
- return Math.random() * (max - min) + min;
-}
-
-/**
- * Returns a random integer between min (inclusive) and max (exclusive).
- *
- * @method randomRangeInt
- * @param {number} min
- * @param {number} max
- * @return {number} the random integer
- */
-function randomRangeInt(min, max) {
- return Math.floor(randomRange(min, max));
-}
-
-/**
- * Returns the next power of two for the value
- *
- * @method nextPow2
- * @param {number} val
- * @return {number} the the next power of two
- */
-function nextPow2(val) {
- --val;
- val = (val >> 1) | val;
- val = (val >> 2) | val;
- val = (val >> 4) | val;
- val = (val >> 8) | val;
- val = (val >> 16) | val;
- ++val;
-
- return val;
-}
-
-/**
- * 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;
-var INT_MAX = 0x7fffffff;
-var INT_MIN = -1<<(INT_BITS-1);
-
-/**
- * Returns -1, 0, +1 depending on sign of x
- *
- * @param {number} v
- * @returns {number}
- */
-function sign(v) {
- return (v > 0) - (v < 0);
-}
-
-/**
- * Computes absolute value of integer
- *
- * @param {number} v
- * @returns {number}
- */
-function abs(v) {
- var mask = v >> (INT_BITS-1);
- return (v ^ mask) - mask;
-}
-
-/**
- * Computes minimum of integers x and y
- *
- * @param {number} x
- * @param {number} y
- * @returns {number}
- */
-function min(x, y) {
- return y ^ ((x ^ y) & -(x < y));
-}
-
-/**
- * Computes maximum of integers x and y
- *
- * @param {number} x
- * @param {number} y
- * @returns {number}
- */
-function max(x, y) {
- return x ^ ((x ^ y) & -(x < y));
-}
-
-/**
- * Checks if a number is a power of two
- *
- * @param {number} v
- * @returns {boolean}
- */
-function isPow2(v) {
- return !(v & (v-1)) && (!!v);
-}
-
-/**
- * Computes log base 2 of v
- *
- * @param {number} v
- * @returns {number}
- */
-function log2(v) {
- var r, shift;
- r = (v > 0xFFFF) << 4; v >>>= r;
- shift = (v > 0xFF ) << 3; v >>>= shift; r |= shift;
- shift = (v > 0xF ) << 2; v >>>= shift; r |= shift;
- shift = (v > 0x3 ) << 1; v >>>= shift; r |= shift;
- return r | (v >> 1);
-}
-
-/**
- * Computes log base 10 of v
- *
- * @param {number} v
- * @returns {number}
- */
-function log10$1(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
- *
- * @param {number} v
- * @returns {number}
- */
-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
- *
- * @param {number} v
- * @returns {number}
- */
-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
- *
- * @param {number} v
- * @returns {number}
- */
-function nextPow2$1(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
- *
- * @param {number} v
- * @returns {number}
- */
-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
- *
- * @param {number} v
- * @returns {number}
- */
-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
- *
- * @param {number} v
- * @returns {number}
- */
-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
- *
- * @param {number} x
- * @param {number} y
- * @returns {number}
- */
-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
- *
- * @param {number} v
- * @param {number} n
- * @returns {number}
- */
-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
- *
- * @param {number} x
- * @param {number} y
- * @param {number} z
- * @returns {number}
- */
-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
- *
- * @param {number} v
- * @param {number} n
- * @returns {number}
- */
-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)
- *
- * @param {number} v
- * @returns {number}
- */
-function nextCombination(v) {
- var t = v | (v - 1);
- return (t + 1) | (((~t & -~t) - 1) >>> (countTrailingZeros(v) + 1));
-}
-
-var bits_ = Object.freeze({
- INT_BITS: INT_BITS,
- INT_MAX: INT_MAX,
- INT_MIN: INT_MIN,
- sign: sign,
- abs: abs,
- min: min,
- max: max,
- isPow2: isPow2,
- log2: log2,
- log10: log10$1,
- popCount: popCount,
- countTrailingZeros: countTrailingZeros,
- nextPow2: nextPow2$1,
- prevPow2: prevPow2,
- parity: parity,
- reverse: reverse,
- interleave2: interleave2,
- deinterleave2: deinterleave2,
- interleave3: interleave3,
- deinterleave3: deinterleave3,
- nextCombination: nextCombination
-});
-
-var _tmp = new Array(2);
-
-var _vec2 = function _vec2(x, y) {
- this.x = x;
- this.y = y;
-};
-
-_vec2.prototype.toJSON = function toJSON () {
- _tmp[0] = this.x;
- _tmp[1] = this.y;
-
- return _tmp;
-};
-
-/**
- * @class 2 Dimensional Vector
- * @name vec2
- */
-var vec2 = {};
-
-/**
- * Creates a new, empty vec2
- *
- * @returns {vec2} a new 2D vector
- */
-vec2.create = function () {
- return new _vec2(0, 0);
-};
-
-/**
- * Creates a new vec2 initialized with the given values
- *
- * @param {Number} x X component
- * @param {Number} y Y component
- * @returns {vec2} a new 2D vector
- */
-vec2.new = function (x, y) {
- return new _vec2(x, y);
-};
-
-/**
- * Creates a new vec2 initialized with values from an existing vector
- *
- * @param {vec2} a vector to clone
- * @returns {vec2} a new 2D vector
- */
-vec2.clone = function (a) {
- return new _vec2(a.x, a.y);
-};
-
-/**
- * Copy the values from one vec2 to another
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the source vector
- * @returns {vec2} out
- */
-vec2.copy = function (out, a) {
- out.x = a.x;
- out.y = a.y;
- return out;
-};
-
-/**
- * Set the components of a vec2 to the given values
- *
- * @param {vec2} out the receiving vector
- * @param {Number} x X component
- * @param {Number} y Y component
- * @returns {vec2} out
- */
-vec2.set = function (out, x, y) {
- out.x = x;
- out.y = y;
- return out;
-};
-
-/**
- * Adds two vec2's
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
- */
-vec2.add = function (out, a, b) {
- out.x = a.x + b.x;
- out.y = a.y + b.y;
- return out;
-};
-
-/**
- * Subtracts vector b from vector a
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
- */
-vec2.subtract = function (out, a, b) {
- out.x = a.x - b.x;
- out.y = a.y - b.y;
- return out;
-};
-
-/**
- * Alias for {@link vec2.subtract}
- * @function
- */
-vec2.sub = vec2.subtract;
-
-/**
- * Multiplies two vec2's
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
- */
-vec2.multiply = function (out, a, b) {
- out.x = a.x * b.x;
- out.y = a.y * b.y;
- return out;
-};
-
-/**
- * Alias for {@link vec2.multiply}
- * @function
- */
-vec2.mul = vec2.multiply;
-
-/**
- * Divides two vec2's
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
- */
-vec2.divide = function (out, a, b) {
- out.x = a.x / b.x;
- out.y = a.y / b.y;
- return out;
-};
-
-/**
- * Alias for {@link vec2.divide}
- * @function
- */
-vec2.div = vec2.divide;
-
-/**
- * Math.ceil the components of a vec2
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to ceil
- * @returns {vec2} out
- */
-vec2.ceil = function (out, a) {
- out.x = Math.ceil(a.x);
- out.y = Math.ceil(a.y);
- return out;
-};
-
-/**
- * Math.floor the components of a vec2
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to floor
- * @returns {vec2} out
- */
-vec2.floor = function (out, a) {
- out.x = Math.floor(a.x);
- out.y = Math.floor(a.y);
- return out;
-};
-
-/**
- * Returns the minimum of two vec2's
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
- */
-vec2.min = function (out, a, b) {
- out.x = Math.min(a.x, b.x);
- out.y = Math.min(a.y, b.y);
- return out;
-};
-
-/**
- * Returns the maximum of two vec2's
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
- */
-vec2.max = function (out, a, b) {
- out.x = Math.max(a.x, b.x);
- out.y = Math.max(a.y, b.y);
- return out;
-};
-
-/**
- * Math.round the components of a vec2
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to round
- * @returns {vec2} out
- */
-vec2.round = function (out, a) {
- out.x = Math.round(a.x);
- out.y = Math.round(a.y);
- return out;
-};
-
-/**
- * Scales a vec2 by a scalar number
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the vector to scale
- * @param {Number} b amount to scale the vector by
- * @returns {vec2} out
- */
-vec2.scale = function (out, a, b) {
- out.x = a.x * b;
- out.y = a.y * b;
- return out;
-};
-
-/**
- * Adds two vec2's after scaling the second operand by a scalar value
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @param {Number} scale the amount to scale b by before adding
- * @returns {vec2} out
- */
-vec2.scaleAndAdd = function (out, a, b, scale) {
- out.x = a.x + (b.x * scale);
- out.y = a.y + (b.y * scale);
- return out;
-};
-
-/**
- * Calculates the euclidian distance between two vec2's
- *
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {Number} distance between a and b
- */
-vec2.distance = function (a, b) {
- var x = b.x - a.x,
- y = b.y - a.y;
- return Math.sqrt(x * x + y * y);
-};
-
-/**
- * Alias for {@link vec2.distance}
- * @function
- */
-vec2.dist = vec2.distance;
-
-/**
- * Calculates the squared euclidian distance between two vec2's
- *
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {Number} squared distance between a and b
- */
-vec2.squaredDistance = function (a, b) {
- var x = b.x - a.x,
- y = b.y - a.y;
- return x * x + y * y;
-};
-
-/**
- * Alias for {@link vec2.squaredDistance}
- * @function
- */
-vec2.sqrDist = vec2.squaredDistance;
-
-/**
- * Calculates the length of a vec2
- *
- * @param {vec2} a vector to calculate length of
- * @returns {Number} length of a
- */
-vec2.length = function (a) {
- var x = a.x,
- y = a.y;
- return Math.sqrt(x * x + y * y);
-};
-
-/**
- * Alias for {@link vec2.length}
- * @function
- */
-vec2.len = vec2.length;
-
-/**
- * Calculates the squared length of a vec2
- *
- * @param {vec2} a vector to calculate squared length of
- * @returns {Number} squared length of a
- */
-vec2.squaredLength = function (a) {
- var x = a.x,
- y = a.y;
- return x * x + y * y;
-};
-
-/**
- * Alias for {@link vec2.squaredLength}
- * @function
- */
-vec2.sqrLen = vec2.squaredLength;
-
-/**
- * Negates the components of a vec2
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to negate
- * @returns {vec2} out
- */
-vec2.negate = function (out, a) {
- out.x = -a.x;
- out.y = -a.y;
- return out;
-};
-
-/**
- * Returns the inverse of the components of a vec2
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to invert
- * @returns {vec2} out
- */
-vec2.inverse = function (out, a) {
- out.x = 1.0 / a.x;
- out.y = 1.0 / a.y;
- return out;
-};
-
-/**
- * Returns the inverse of the components of a vec2 safely
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to invert
- * @returns {vec2} out
- */
-vec2.inverseSafe = function (out, a) {
- var x = a.x,
- y = a.y;
-
- if (Math.abs(x) < EPSILON) {
- out.x = 0;
- } else {
- out.x = 1.0 / x;
- }
-
- if (Math.abs(y) < EPSILON) {
- out.y = 0;
- } else {
- out.y = 1.0 / a.y;
- }
-
- return out;
-};
-
-/**
- * Normalize a vec2
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to normalize
- * @returns {vec2} out
- */
-vec2.normalize = function (out, a) {
- var x = a.x,
- y = a.y;
- var len = x * x + y * y;
- if (len > 0) {
- //TODO: evaluate use of glm_invsqrt here?
- len = 1 / Math.sqrt(len);
- out.x = a.x * len;
- out.y = a.y * len;
- }
- return out;
-};
-
-/**
- * Calculates the dot product of two vec2's
- *
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {Number} dot product of a and b
- */
-vec2.dot = function (a, b) {
- return a.x * b.x + a.y * b.y;
-};
-
-/**
- * Computes the cross product of two vec2's
- * Note that the cross product must by definition produce a 3D vector
- *
- * @param {vec3} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec3} out
- */
-vec2.cross = function (out, a, b) {
- var z = a.x * b.y - a.y * b.x;
- out.x = out.y = 0;
- out.z = z;
- return out;
-};
-
-/**
- * Performs a linear interpolation between two vec2's
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {vec2} out
- */
-vec2.lerp = function (out, a, b, t) {
- var ax = a.x,
- ay = a.y;
- out.x = ax + t * (b.x - ax);
- out.y = ay + t * (b.y - ay);
- return out;
-};
-
-/**
- * Generates a random vector with the given scale
- *
- * @param {vec2} out the receiving vector
- * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
- * @returns {vec2} out
- */
-vec2.random = function (out, scale) {
- scale = scale || 1.0;
- var r = random() * 2.0 * Math.PI;
- out.x = Math.cos(r) * scale;
- out.y = Math.sin(r) * scale;
- return out;
-};
-
-/**
- * Transforms the vec2 with a mat2
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the vector to transform
- * @param {mat2} m matrix to transform with
- * @returns {vec2} out
- */
-vec2.transformMat2 = function (out, a, m) {
- var x = a.x,
- y = a.y;
- out.x = m.m00 * x + m.m02 * y;
- out.y = m.m01 * x + m.m03 * y;
- return out;
-};
-
-/**
- * Transforms the vec2 with a mat23
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the vector to transform
- * @param {mat23} m matrix to transform with
- * @returns {vec2} out
- */
-vec2.transformMat23 = function (out, a, m) {
- var x = a.x,
- y = a.y;
- out.x = m.m00 * x + m.m02 * y + m.m04;
- out.y = m.m01 * x + m.m03 * y + m.m05;
- return out;
-};
-
-/**
- * Transforms the vec2 with a mat3
- * 3rd vector component is implicitly '1'
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the vector to transform
- * @param {mat3} m matrix to transform with
- * @returns {vec2} out
- */
-vec2.transformMat3 = function (out, a, m) {
- var x = a.x,
- y = a.y;
- out.x = m.m00 * x + m.m03 * y + m.m06;
- out.y = m.m01 * x + m.m04 * y + m.m07;
- return out;
-};
-
-/**
- * Transforms the vec2 with a mat4
- * 3rd vector component is implicitly '0'
- * 4th vector component is implicitly '1'
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the vector to transform
- * @param {mat4} m matrix to transform with
- * @returns {vec2} out
- */
-vec2.transformMat4 = function (out, a, m) {
- var x = a.x,
- y = a.y;
- out.x = m.m00 * x + m.m04 * y + m.m12;
- out.y = m.m01 * x + m.m05 * y + m.m13;
- return out;
-};
-
-/**
- * Perform some operation over an array of vec2s.
- *
- * @param {Array} a the array of vectors to iterate over
- * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
- * @param {Number} offset Number of elements to skip at the beginning of the array
- * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
- * @param {Function} fn Function to call for each vector in the array
- * @param {Object} [arg] additional argument to pass to fn
- * @returns {Array} a
- * @function
- */
-vec2.forEach = (function () {
- var vec = vec2.create();
-
- return function (a, stride, offset, count, fn, arg) {
- var i, l;
- if (!stride) {
- stride = 2;
- }
-
- if (!offset) {
- offset = 0;
- }
-
- if (count) {
- l = Math.min((count * stride) + offset, a.length);
- } else {
- l = a.length;
- }
-
- for (i = offset; i < l; i += stride) {
- vec.x = a[i]; vec.y = a[i + 1];
- fn(vec, vec, arg);
- a[i] = vec.x; a[i + 1] = vec.y;
- }
-
- return a;
- };
-})();
-
-/**
- * Returns a string representation of a vector
- *
- * @param {vec2} a vector to represent as a string
- * @returns {String} string representation of the vector
- */
-vec2.str = function (a) {
- return ("vec2(" + (a.x) + ", " + (a.y) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {vec2} v
- * @returns {array}
- */
-vec2.array = function (out, v) {
- out[0] = v.x;
- out[1] = v.y;
-
- return out;
-};
-
-/**
- * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)
- *
- * @param {vec2} a The first vector.
- * @param {vec2} b The second vector.
- * @returns {Boolean} True if the vectors are equal, false otherwise.
- */
-vec2.exactEquals = function (a, b) {
- return a.x === b.x && a.y === b.y;
-};
-
-/**
- * Returns whether or not the vectors have approximately the same elements in the same position.
- *
- * @param {vec2} a The first vector.
- * @param {vec2} b The second vector.
- * @returns {Boolean} True if the vectors are equal, false otherwise.
- */
-vec2.equals = function (a, b) {
- var a0 = a.x, a1 = a.y;
- var b0 = b.x, b1 = b.y;
- return (Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)));
-};
-
-var _tmp$1 = new Array(3);
-
-var _vec3 = function _vec3(x, y, z) {
- this.x = x;
- this.y = y;
- this.z = z;
-};
-
-_vec3.prototype.toJSON = function toJSON () {
- _tmp$1[0] = this.x;
- _tmp$1[1] = this.y;
- _tmp$1[2] = this.z;
-
- return _tmp$1;
-};
-
-/**
- * @class 3 Dimensional Vector
- * @name vec3
- */
-var vec3 = {};
-
-/**
- * Creates a new, empty vec3
- *
- * @returns {vec3} a new 3D vector
- */
-vec3.create = function () {
- return new _vec3(0, 0, 0);
-};
-
-/**
- * Creates a new vec3 initialized with the given values
- *
- * @param {Number} x X component
- * @param {Number} y Y component
- * @param {Number} z Z component
- * @returns {vec3} a new 3D vector
- */
-vec3.new = function (x, y, z) {
- return new _vec3(x, y, z);
-};
-
-/**
- * Creates a new vec3 initialized with values from an existing vector
- *
- * @param {vec3} a vector to clone
- * @returns {vec3} a new 3D vector
- */
-vec3.clone = function (a) {
- return new _vec3(a.x, a.y, a.z);
-};
-
-/**
- * Copy the values from one vec3 to another
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the source vector
- * @returns {vec3} out
- */
-vec3.copy = function (out, a) {
- out.x = a.x;
- out.y = a.y;
- out.z = a.z;
- return out;
-};
-
-/**
- * Set the components of a vec3 to the given values
- *
- * @param {vec3} out the receiving vector
- * @param {Number} x X component
- * @param {Number} y Y component
- * @param {Number} z Z component
- * @returns {vec3} out
- */
-vec3.set = function (out, x, y, z) {
- out.x = x;
- out.y = y;
- out.z = z;
- return out;
-};
-
-/**
- * Adds two vec3's
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.add = function (out, a, b) {
- out.x = a.x + b.x;
- out.y = a.y + b.y;
- out.z = a.z + b.z;
- return out;
-};
-
-/**
- * Subtracts vector b from vector a
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.subtract = function (out, a, b) {
- out.x = a.x - b.x;
- out.y = a.y - b.y;
- out.z = a.z - b.z;
- return out;
-};
-
-/**
- * Alias for {@link vec3.subtract}
- * @function
- */
-vec3.sub = vec3.subtract;
-
-/**
- * Multiplies two vec3's
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.multiply = function (out, a, b) {
- out.x = a.x * b.x;
- out.y = a.y * b.y;
- out.z = a.z * b.z;
- return out;
-};
-
-/**
- * Alias for {@link vec3.multiply}
- * @function
- */
-vec3.mul = vec3.multiply;
-
-/**
- * Divides two vec3's
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.divide = function (out, a, b) {
- out.x = a.x / b.x;
- out.y = a.y / b.y;
- out.z = a.z / b.z;
- return out;
-};
-
-/**
- * Alias for {@link vec3.divide}
- * @function
- */
-vec3.div = vec3.divide;
-
-/**
- * Math.ceil the components of a vec3
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a vector to ceil
- * @returns {vec3} out
- */
-vec3.ceil = function (out, a) {
- out.x = Math.ceil(a.x);
- out.y = Math.ceil(a.y);
- out.z = Math.ceil(a.z);
- return out;
-};
-
-/**
- * Math.floor the components of a vec3
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a vector to floor
- * @returns {vec3} out
- */
-vec3.floor = function (out, a) {
- out.x = Math.floor(a.x);
- out.y = Math.floor(a.y);
- out.z = Math.floor(a.z);
- return out;
-};
-
-/**
- * Returns the minimum of two vec3's
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.min = function (out, a, b) {
- out.x = Math.min(a.x, b.x);
- out.y = Math.min(a.y, b.y);
- out.z = Math.min(a.z, b.z);
- return out;
-};
-
-/**
- * Returns the maximum of two vec3's
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.max = function (out, a, b) {
- out.x = Math.max(a.x, b.x);
- out.y = Math.max(a.y, b.y);
- out.z = Math.max(a.z, b.z);
- return out;
-};
-
-/**
- * Math.round the components of a vec3
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a vector to round
- * @returns {vec3} out
- */
-vec3.round = function (out, a) {
- out.x = Math.round(a.x);
- out.y = Math.round(a.y);
- out.z = Math.round(a.z);
- return out;
-};
-
-/**
- * Scales a vec3 by a scalar number
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the vector to scale
- * @param {Number} b amount to scale the vector by
- * @returns {vec3} out
- */
-vec3.scale = function (out, a, b) {
- out.x = a.x * b;
- out.y = a.y * b;
- out.z = a.z * b;
- return out;
-};
-
-/**
- * Adds two vec3's after scaling the second operand by a scalar value
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @param {Number} scale the amount to scale b by before adding
- * @returns {vec3} out
- */
-vec3.scaleAndAdd = function (out, a, b, scale) {
- out.x = a.x + (b.x * scale);
- out.y = a.y + (b.y * scale);
- out.z = a.z + (b.z * scale);
- return out;
-};
-
-/**
- * Calculates the euclidian distance between two vec3's
- *
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {Number} distance between a and b
- */
-vec3.distance = function (a, b) {
- var x = b.x - a.x,
- y = b.y - a.y,
- z = b.z - a.z;
- return Math.sqrt(x * x + y * y + z * z);
-};
-
-/**
- * Alias for {@link vec3.distance}
- * @function
- */
-vec3.dist = vec3.distance;
-
-/**
- * Calculates the squared euclidian distance between two vec3's
- *
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {Number} squared distance between a and b
- */
-vec3.squaredDistance = function (a, b) {
- var x = b.x - a.x,
- y = b.y - a.y,
- z = b.z - a.z;
- return x * x + y * y + z * z;
-};
-
-/**
- * Alias for {@link vec3.squaredDistance}
- * @function
- */
-vec3.sqrDist = vec3.squaredDistance;
-
-/**
- * Calculates the length of a vec3
- *
- * @param {vec3} a vector to calculate length of
- * @returns {Number} length of a
- */
-vec3.length = function (a) {
- var x = a.x,
- y = a.y,
- z = a.z;
- return Math.sqrt(x * x + y * y + z * z);
-};
-
-/**
- * Alias for {@link vec3.length}
- * @function
- */
-vec3.len = vec3.length;
-
-/**
- * Calculates the squared length of a vec3
- *
- * @param {vec3} a vector to calculate squared length of
- * @returns {Number} squared length of a
- */
-vec3.squaredLength = function (a) {
- var x = a.x,
- y = a.y,
- z = a.z;
- return x * x + y * y + z * z;
-};
-
-/**
- * Alias for {@link vec3.squaredLength}
- * @function
- */
-vec3.sqrLen = vec3.squaredLength;
-
-/**
- * Negates the components of a vec3
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a vector to negate
- * @returns {vec3} out
- */
-vec3.negate = function (out, a) {
- out.x = -a.x;
- out.y = -a.y;
- out.z = -a.z;
- return out;
-};
-
-/**
- * Returns the inverse of the components of a vec3
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a vector to invert
- * @returns {vec3} out
- */
-vec3.inverse = function (out, a) {
- out.x = 1.0 / a.x;
- out.y = 1.0 / a.y;
- out.z = 1.0 / a.z;
- return out;
-};
-
-/**
- * Returns the inverse of the components of a vec3 safely
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a vector to invert
- * @returns {vec3} out
- */
-vec3.inverseSafe = function (out, a) {
- var x = a.x,
- y = a.y,
- z = a.z;
-
- if (Math.abs(x) < EPSILON) {
- out.x = 0;
- } else {
- out.x = 1.0 / x;
- }
-
- if (Math.abs(y) < EPSILON) {
- out.y = 0;
- } else {
- out.y = 1.0 / y;
- }
-
- if (Math.abs(z) < EPSILON) {
- out.z = 0;
- } else {
- out.z = 1.0 / z;
- }
-
- return out;
-};
-
-/**
- * Normalize a vec3
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a vector to normalize
- * @returns {vec3} out
- */
-vec3.normalize = function (out, a) {
- var x = a.x,
- y = a.y,
- z = a.z;
-
- var len = x * x + y * y + z * z;
- if (len > 0) {
- //TODO: evaluate use of glm_invsqrt here?
- len = 1 / Math.sqrt(len);
- out.x = x * len;
- out.y = y * len;
- out.z = z * len;
- }
- return out;
-};
-
-/**
- * Calculates the dot product of two vec3's
- *
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {Number} dot product of a and b
- */
-vec3.dot = function (a, b) {
- return a.x * b.x + a.y * b.y + a.z * b.z;
-};
-
-/**
- * Computes the cross product of two vec3's
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.cross = function (out, a, b) {
- var ax = a.x, ay = a.y, az = a.z,
- bx = b.x, by = b.y, bz = b.z;
-
- out.x = ay * bz - az * by;
- out.y = az * bx - ax * bz;
- out.z = ax * by - ay * bx;
- return out;
-};
-
-/**
- * Performs a linear interpolation between two vec3's
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {vec3} out
- */
-vec3.lerp = function (out, a, b, t) {
- var ax = a.x,
- ay = a.y,
- az = a.z;
- out.x = ax + t * (b.x - ax);
- out.y = ay + t * (b.y - ay);
- out.z = az + t * (b.z - az);
- return out;
-};
-
-/**
- * Performs a hermite interpolation with two control points
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @param {vec3} c the third operand
- * @param {vec3} d the fourth operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {vec3} out
- */
-vec3.hermite = function (out, a, b, c, d, t) {
- var factorTimes2 = t * t,
- factor1 = factorTimes2 * (2 * t - 3) + 1,
- factor2 = factorTimes2 * (t - 2) + t,
- factor3 = factorTimes2 * (t - 1),
- factor4 = factorTimes2 * (3 - 2 * t);
-
- out.x = a.x * factor1 + b.x * factor2 + c.x * factor3 + d.x * factor4;
- out.y = a.y * factor1 + b.y * factor2 + c.y * factor3 + d.y * factor4;
- out.z = a.z * factor1 + b.z * factor2 + c.z * factor3 + d.z * factor4;
-
- return out;
-};
-
-/**
- * Performs a bezier interpolation with two control points
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @param {vec3} c the third operand
- * @param {vec3} d the fourth operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {vec3} out
- */
-vec3.bezier = function (out, a, b, c, d, t) {
- var inverseFactor = 1 - t,
- inverseFactorTimesTwo = inverseFactor * inverseFactor,
- factorTimes2 = t * t,
- factor1 = inverseFactorTimesTwo * inverseFactor,
- factor2 = 3 * t * inverseFactorTimesTwo,
- factor3 = 3 * factorTimes2 * inverseFactor,
- factor4 = factorTimes2 * t;
-
- out.x = a.x * factor1 + b.x * factor2 + c.x * factor3 + d.x * factor4;
- out.y = a.y * factor1 + b.y * factor2 + c.y * factor3 + d.y * factor4;
- out.z = a.z * factor1 + b.z * factor2 + c.z * factor3 + d.z * factor4;
-
- return out;
-};
-
-/**
- * Generates a random vector with the given scale
- *
- * @param {vec3} out the receiving vector
- * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
- * @returns {vec3} out
- */
-vec3.random = function (out, scale) {
- scale = scale || 1.0;
-
- var r = random() * 2.0 * Math.PI;
- var z = (random() * 2.0) - 1.0;
- var zScale = Math.sqrt(1.0 - z * z) * scale;
-
- out.x = Math.cos(r) * zScale;
- out.y = Math.sin(r) * zScale;
- out.z = z * scale;
- return out;
-};
-
-/**
- * Transforms the vec3 with a mat4.
- * 4th vector component is implicitly '1'
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the vector to transform
- * @param {mat4} m matrix to transform with
- * @returns {vec3} out
- */
-vec3.transformMat4 = function (out, a, m) {
- var x = a.x, y = a.y, z = a.z,
- w = m.m03 * x + m.m07 * y + m.m11 * z + m.m15;
- w = w || 1.0;
- out.x = (m.m00 * x + m.m04 * y + m.m08 * z + m.m12) / w;
- out.y = (m.m01 * x + m.m05 * y + m.m09 * z + m.m13) / w;
- out.z = (m.m02 * x + m.m06 * y + m.m10 * z + m.m14) / w;
- return out;
-};
-
-/**
- * Transforms the vec3 with a mat3.
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the vector to transform
- * @param {mat4} m the 3x3 matrix to transform with
- * @returns {vec3} out
- */
-vec3.transformMat3 = function (out, a, m) {
- var x = a.x, y = a.y, z = a.z;
- out.x = x * m.m00 + y * m.m03 + z * m.m06;
- out.y = x * m.m01 + y * m.m04 + z * m.m07;
- out.z = x * m.m02 + y * m.m05 + z * m.m08;
- return out;
-};
-
-/**
- * Transforms the vec3 with a quat
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the vector to transform
- * @param {quat} q quaternion to transform with
- * @returns {vec3} out
- */
-vec3.transformQuat = function (out, a, q) {
- // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations
-
- var x = a.x, y = a.y, z = a.z;
- var qx = q.x, qy = q.y, qz = q.z, qw = q.w;
-
- // calculate quat * vec
- var ix = qw * x + qy * z - qz * y;
- var iy = qw * y + qz * x - qx * z;
- var iz = qw * z + qx * y - qy * x;
- var iw = -qx * x - qy * y - qz * z;
-
- // calculate result * inverse quat
- out.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
- out.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
- out.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
- return out;
-};
-
-/**
- * Rotate a 3D vector around the x-axis
- * @param {vec3} out The receiving vec3
- * @param {vec3} a The vec3 point to rotate
- * @param {vec3} b The origin of the rotation
- * @param {Number} c The angle of rotation
- * @returns {vec3} out
- */
-vec3.rotateX = function (out, a, b, c) {
- var p = [], r = [];
- // Translate point to the origin
- p.x = a.x - b.x;
- p.y = a.y - b.y;
- p.z = a.z - b.z;
-
- //perform rotation
- r.x = p.x;
- r.y = p.y * Math.cos(c) - p.z * Math.sin(c);
- r.z = p.y * Math.sin(c) + p.z * Math.cos(c);
-
- //translate to correct position
- out.x = r.x + b.x;
- out.y = r.y + b.y;
- out.z = r.z + b.z;
-
- return out;
-};
-
-/**
- * Rotate a 3D vector around the y-axis
- * @param {vec3} out The receiving vec3
- * @param {vec3} a The vec3 point to rotate
- * @param {vec3} b The origin of the rotation
- * @param {Number} c The angle of rotation
- * @returns {vec3} out
- */
-vec3.rotateY = function (out, a, b, c) {
- var p = [], r = [];
- //Translate point to the origin
- p.x = a.x - b.x;
- p.y = a.y - b.y;
- p.z = a.z - b.z;
-
- //perform rotation
- r.x = p.z * Math.sin(c) + p.x * Math.cos(c);
- r.y = p.y;
- r.z = p.z * Math.cos(c) - p.x * Math.sin(c);
-
- //translate to correct position
- out.x = r.x + b.x;
- out.y = r.y + b.y;
- out.z = r.z + b.z;
-
- return out;
-};
-
-/**
- * Rotate a 3D vector around the z-axis
- * @param {vec3} out The receiving vec3
- * @param {vec3} a The vec3 point to rotate
- * @param {vec3} b The origin of the rotation
- * @param {Number} c The angle of rotation
- * @returns {vec3} out
- */
-vec3.rotateZ = function (out, a, b, c) {
- var p = [], r = [];
- //Translate point to the origin
- p.x = a.x - b.x;
- p.y = a.y - b.y;
- p.z = a.z - b.z;
-
- //perform rotation
- r.x = p.x * Math.cos(c) - p.y * Math.sin(c);
- r.y = p.x * Math.sin(c) + p.y * Math.cos(c);
- r.z = p.z;
-
- //translate to correct position
- out.x = r.x + b.x;
- out.y = r.y + b.y;
- out.z = r.z + b.z;
-
- return out;
-};
-
-/**
- * Perform some operation over an array of vec3s.
- *
- * @param {Array} a the array of vectors to iterate over
- * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
- * @param {Number} offset Number of elements to skip at the beginning of the array
- * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
- * @param {Function} fn Function to call for each vector in the array
- * @param {Object} [arg] additional argument to pass to fn
- * @returns {Array} a
- * @function
- */
-vec3.forEach = (function () {
- var vec = vec3.create();
-
- return function (a, stride, offset, count, fn, arg) {
- var i, l;
- if (!stride) {
- stride = 3;
- }
-
- if (!offset) {
- offset = 0;
- }
-
- if (count) {
- l = Math.min((count * stride) + offset, a.length);
- } else {
- l = a.length;
- }
-
- for (i = offset; i < l; i += stride) {
- vec.x = a[i]; vec.y = a[i + 1]; vec.z = a[i + 2];
- fn(vec, vec, arg);
- a[i] = vec.x; a[i + 1] = vec.y; a[i + 2] = vec.z;
- }
-
- return a;
- };
-})();
-
-/**
- * Get the angle between two 3D vectors
- * @param {vec3} a The first operand
- * @param {vec3} b The second operand
- * @returns {Number} The angle in radians
- */
-vec3.angle = (function () {
- var tempA = vec3.create();
- var tempB = vec3.create();
-
- return function (a, b) {
- vec3.copy(tempA, a);
- vec3.copy(tempB, b);
-
- vec3.normalize(tempA, tempA);
- vec3.normalize(tempB, tempB);
-
- var cosine = vec3.dot(tempA, tempB);
-
- if (cosine > 1.0) {
- return 0;
- }
-
- if (cosine < -1.0) {
- return Math.PI;
- }
-
- return Math.acos(cosine);
- };
-})();
-
-/**
- * Returns a string representation of a vector
- *
- * @param {vec3} a vector to represent as a string
- * @returns {String} string representation of the vector
- */
-vec3.str = function (a) {
- return ("vec3(" + (a.x) + ", " + (a.y) + ", " + (a.z) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {vec3} v
- * @returns {array}
- */
-vec3.array = function (out, v) {
- out[0] = v.x;
- out[1] = v.y;
- out[2] = v.z;
-
- return out;
-};
-
-/**
- * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
- *
- * @param {vec3} a The first vector.
- * @param {vec3} b The second vector.
- * @returns {Boolean} True if the vectors are equal, false otherwise.
- */
-vec3.exactEquals = function (a, b) {
- return a.x === b.x && a.y === b.y && a.z === b.z;
-};
-
-/**
- * Returns whether or not the vectors have approximately the same elements in the same position.
- *
- * @param {vec3} a The first vector.
- * @param {vec3} b The second vector.
- * @returns {Boolean} True if the vectors are equal, false otherwise.
- */
-vec3.equals = function (a, b) {
- var a0 = a.x, a1 = a.y, a2 = a.z;
- var b0 = b.x, b1 = b.y, b2 = b.z;
- return (Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
- Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)));
-};
-
-var _tmp$2 = new Array(4);
-
-var _vec4 = function _vec4(x, y, z, w) {
- this.x = x;
- this.y = y;
- this.z = z;
- this.w = w;
-};
-
-_vec4.prototype.toJSON = function toJSON () {
- _tmp$2[0] = this.x;
- _tmp$2[1] = this.y;
- _tmp$2[2] = this.z;
- _tmp$2[3] = this.w;
-
- return _tmp$2;
-};
-
-/**
- * @class 4 Dimensional Vector
- * @name vec4
- */
-var vec4 = {};
-
-/**
- * Creates a new, empty vec4
- *
- * @returns {vec4} a new 4D vector
- */
-vec4.create = function () {
- return new _vec4(0, 0, 0, 0);
-};
-
-/**
- * Creates a new vec4 initialized with the given values
- *
- * @param {Number} x X component
- * @param {Number} y Y component
- * @param {Number} z Z component
- * @param {Number} w W component
- * @returns {vec4} a new 4D vector
- */
-vec4.new = function (x, y, z, w) {
- return new _vec4(x, y, z, w);
-};
-
-/**
- * Creates a new vec4 initialized with values from an existing vector
- *
- * @param {vec4} a vector to clone
- * @returns {vec4} a new 4D vector
- */
-vec4.clone = function (a) {
- return new _vec4(a.x, a.y, a.z, a.w);
-};
-
-/**
- * Copy the values from one vec4 to another
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the source vector
- * @returns {vec4} out
- */
-vec4.copy = function (out, a) {
- out.x = a.x;
- out.y = a.y;
- out.z = a.z;
- out.w = a.w;
- return out;
-};
-
-/**
- * Set the components of a vec4 to the given values
- *
- * @param {vec4} out the receiving vector
- * @param {Number} x X component
- * @param {Number} y Y component
- * @param {Number} z Z component
- * @param {Number} w W component
- * @returns {vec4} out
- */
-vec4.set = function (out, x, y, z, w) {
- out.x = x;
- out.y = y;
- out.z = z;
- out.w = w;
- return out;
-};
-
-/**
- * Adds two vec4's
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {vec4} out
- */
-vec4.add = function (out, a, b) {
- out.x = a.x + b.x;
- out.y = a.y + b.y;
- out.z = a.z + b.z;
- out.w = a.w + b.w;
- return out;
-};
-
-/**
- * Subtracts vector b from vector a
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {vec4} out
- */
-vec4.subtract = function (out, a, b) {
- out.x = a.x - b.x;
- out.y = a.y - b.y;
- out.z = a.z - b.z;
- out.w = a.w - b.w;
- return out;
-};
-
-/**
- * Alias for {@link vec4.subtract}
- * @function
- */
-vec4.sub = vec4.subtract;
-
-/**
- * Multiplies two vec4's
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {vec4} out
- */
-vec4.multiply = function (out, a, b) {
- out.x = a.x * b.x;
- out.y = a.y * b.y;
- out.z = a.z * b.z;
- out.w = a.w * b.w;
- return out;
-};
-
-/**
- * Alias for {@link vec4.multiply}
- * @function
- */
-vec4.mul = vec4.multiply;
-
-/**
- * Divides two vec4's
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {vec4} out
- */
-vec4.divide = function (out, a, b) {
- out.x = a.x / b.x;
- out.y = a.y / b.y;
- out.z = a.z / b.z;
- out.w = a.w / b.w;
- return out;
-};
-
-/**
- * Alias for {@link vec4.divide}
- * @function
- */
-vec4.div = vec4.divide;
-
-/**
- * Math.ceil the components of a vec4
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a vector to ceil
- * @returns {vec4} out
- */
-vec4.ceil = function (out, a) {
- out.x = Math.ceil(a.x);
- out.y = Math.ceil(a.y);
- out.z = Math.ceil(a.z);
- out.w = Math.ceil(a.w);
- return out;
-};
-
-/**
- * Math.floor the components of a vec4
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a vector to floor
- * @returns {vec4} out
- */
-vec4.floor = function (out, a) {
- out.x = Math.floor(a.x);
- out.y = Math.floor(a.y);
- out.z = Math.floor(a.z);
- out.w = Math.floor(a.w);
- return out;
-};
-
-/**
- * Returns the minimum of two vec4's
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {vec4} out
- */
-vec4.min = function (out, a, b) {
- out.x = Math.min(a.x, b.x);
- out.y = Math.min(a.y, b.y);
- out.z = Math.min(a.z, b.z);
- out.w = Math.min(a.w, b.w);
- return out;
-};
-
-/**
- * Returns the maximum of two vec4's
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {vec4} out
- */
-vec4.max = function (out, a, b) {
- out.x = Math.max(a.x, b.x);
- out.y = Math.max(a.y, b.y);
- out.z = Math.max(a.z, b.z);
- out.w = Math.max(a.w, b.w);
- return out;
-};
-
-/**
- * Math.round the components of a vec4
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a vector to round
- * @returns {vec4} out
- */
-vec4.round = function (out, a) {
- out.x = Math.round(a.x);
- out.y = Math.round(a.y);
- out.z = Math.round(a.z);
- out.w = Math.round(a.w);
- return out;
-};
-
-/**
- * Scales a vec4 by a scalar number
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the vector to scale
- * @param {Number} b amount to scale the vector by
- * @returns {vec4} out
- */
-vec4.scale = function (out, a, b) {
- out.x = a.x * b;
- out.y = a.y * b;
- out.z = a.z * b;
- out.w = a.w * b;
- return out;
-};
-
-/**
- * Adds two vec4's after scaling the second operand by a scalar value
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @param {Number} scale the amount to scale b by before adding
- * @returns {vec4} out
- */
-vec4.scaleAndAdd = function (out, a, b, scale) {
- out.x = a.x + (b.x * scale);
- out.y = a.y + (b.y * scale);
- out.z = a.z + (b.z * scale);
- out.w = a.w + (b.w * scale);
- return out;
-};
-
-/**
- * Calculates the euclidian distance between two vec4's
- *
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {Number} distance between a and b
- */
-vec4.distance = function (a, b) {
- var x = b.x - a.x,
- y = b.y - a.y,
- z = b.z - a.z,
- w = b.w - a.w;
- return Math.sqrt(x * x + y * y + z * z + w * w);
-};
-
-/**
- * Alias for {@link vec4.distance}
- * @function
- */
-vec4.dist = vec4.distance;
-
-/**
- * Calculates the squared euclidian distance between two vec4's
- *
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {Number} squared distance between a and b
- */
-vec4.squaredDistance = function (a, b) {
- var x = b.x - a.x,
- y = b.y - a.y,
- z = b.z - a.z,
- w = b.w - a.w;
- return x * x + y * y + z * z + w * w;
-};
-
-/**
- * Alias for {@link vec4.squaredDistance}
- * @function
- */
-vec4.sqrDist = vec4.squaredDistance;
-
-/**
- * Calculates the length of a vec4
- *
- * @param {vec4} a vector to calculate length of
- * @returns {Number} length of a
- */
-vec4.length = function (a) {
- var x = a.x,
- y = a.y,
- z = a.z,
- w = a.w;
- return Math.sqrt(x * x + y * y + z * z + w * w);
-};
-
-/**
- * Alias for {@link vec4.length}
- * @function
- */
-vec4.len = vec4.length;
-
-/**
- * Calculates the squared length of a vec4
- *
- * @param {vec4} a vector to calculate squared length of
- * @returns {Number} squared length of a
- */
-vec4.squaredLength = function (a) {
- var x = a.x,
- y = a.y,
- z = a.z,
- w = a.w;
- return x * x + y * y + z * z + w * w;
-};
-
-/**
- * Alias for {@link vec4.squaredLength}
- * @function
- */
-vec4.sqrLen = vec4.squaredLength;
-
-/**
- * Negates the components of a vec4
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a vector to negate
- * @returns {vec4} out
- */
-vec4.negate = function (out, a) {
- out.x = -a.x;
- out.y = -a.y;
- out.z = -a.z;
- out.w = -a.w;
- return out;
-};
-
-/**
- * Returns the inverse of the components of a vec4
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a vector to invert
- * @returns {vec4} out
- */
-vec4.inverse = function (out, a) {
- out.x = 1.0 / a.x;
- out.y = 1.0 / a.y;
- out.z = 1.0 / a.z;
- out.w = 1.0 / a.w;
- return out;
-};
-
-/**
- * Returns the inverse of the components of a vec4 safely
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a vector to invert
- * @returns {vec4} out
- */
-vec4.inverseSafe = function (out, a) {
- var x = a.x,
- y = a.y,
- z = a.z,
- w = a.w;
-
- if (Math.abs(x) < EPSILON) {
- out.x = 0;
- } else {
- out.x = 1.0 / x;
- }
-
- if (Math.abs(y) < EPSILON) {
- out.y = 0;
- } else {
- out.y = 1.0 / y;
- }
-
- if (Math.abs(z) < EPSILON) {
- out.z = 0;
- } else {
- out.z = 1.0 / z;
- }
-
- if (Math.abs(w) < EPSILON) {
- out.w = 0;
- } else {
- out.w = 1.0 / w;
- }
-
- return out;
-};
-
-/**
- * Normalize a vec4
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a vector to normalize
- * @returns {vec4} out
- */
-vec4.normalize = function (out, a) {
- var x = a.x,
- y = a.y,
- z = a.z,
- w = a.w;
- var len = x * x + y * y + z * z + w * w;
- if (len > 0) {
- len = 1 / Math.sqrt(len);
- out.x = x * len;
- out.y = y * len;
- out.z = z * len;
- out.w = w * len;
- }
- return out;
-};
-
-/**
- * Calculates the dot product of two vec4's
- *
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {Number} dot product of a and b
- */
-vec4.dot = function (a, b) {
- return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
-};
-
-/**
- * Performs a linear interpolation between two vec4's
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {vec4} out
- */
-vec4.lerp = function (out, a, b, t) {
- var ax = a.x,
- ay = a.y,
- az = a.z,
- aw = a.w;
- out.x = ax + t * (b.x - ax);
- out.y = ay + t * (b.y - ay);
- out.z = az + t * (b.z - az);
- out.w = aw + t * (b.w - aw);
- return out;
-};
-
-/**
- * Generates a random vector with the given scale
- *
- * @param {vec4} out the receiving vector
- * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
- * @returns {vec4} out
- */
-vec4.random = function (out, scale) {
- scale = scale || 1.0;
-
- //TODO: This is a pretty awful way of doing this. Find something better.
- out.x = random();
- out.y = random();
- out.z = random();
- out.w = random();
- vec4.normalize(out, out);
- vec4.scale(out, out, scale);
- return out;
-};
-
-/**
- * Transforms the vec4 with a mat4.
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the vector to transform
- * @param {mat4} m matrix to transform with
- * @returns {vec4} out
- */
-vec4.transformMat4 = function (out, a, m) {
- var x = a.x, y = a.y, z = a.z, w = a.w;
- out.x = m.m00 * x + m.m04 * y + m.m08 * z + m.m12 * w;
- out.y = m.m01 * x + m.m05 * y + m.m09 * z + m.m13 * w;
- out.z = m.m02 * x + m.m06 * y + m.m10 * z + m.m14 * w;
- out.w = m.m03 * x + m.m07 * y + m.m11 * z + m.m15 * w;
- return out;
-};
-
-/**
- * Transforms the vec4 with a quat
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the vector to transform
- * @param {quat} q quaternion to transform with
- * @returns {vec4} out
- */
-vec4.transformQuat = function (out, a, q) {
- var x = a.x, y = a.y, z = a.z;
- var qx = q.x, qy = q.y, qz = q.z, qw = q.w;
-
- // calculate quat * vec
- var ix = qw * x + qy * z - qz * y;
- var iy = qw * y + qz * x - qx * z;
- var iz = qw * z + qx * y - qy * x;
- var iw = -qx * x - qy * y - qz * z;
-
- // calculate result * inverse quat
- out.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
- out.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
- out.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
- out.w = a.w;
- return out;
-};
-
-/**
- * Perform some operation over an array of vec4s.
- *
- * @param {Array} a the array of vectors to iterate over
- * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
- * @param {Number} offset Number of elements to skip at the beginning of the array
- * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array
- * @param {Function} fn Function to call for each vector in the array
- * @param {Object} [arg] additional argument to pass to fn
- * @returns {Array} a
- * @function
- */
-vec4.forEach = (function () {
- var vec = vec4.create();
-
- return function (a, stride, offset, count, fn, arg) {
- var i, l;
- if (!stride) {
- stride = 4;
- }
-
- if (!offset) {
- offset = 0;
- }
-
- if (count) {
- l = Math.min((count * stride) + offset, a.length);
- } else {
- l = a.length;
- }
-
- for (i = offset; i < l; i += stride) {
- vec.x = a[i]; vec.y = a[i + 1]; vec.z = a[i + 2]; vec.w = a[i + 3];
- fn(vec, vec, arg);
- a[i] = vec.x; a[i + 1] = vec.y; a[i + 2] = vec.z; a[i + 3] = vec.w;
- }
-
- return a;
- };
-})();
-
-/**
- * Returns a string representation of a vector
- *
- * @param {vec4} a vector to represent as a string
- * @returns {String} string representation of the vector
- */
-vec4.str = function (a) {
- return ("vec4(" + (a.x) + ", " + (a.y) + ", " + (a.z) + ", " + (a.w) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {vec4} v
- * @returns {array}
- */
-vec4.array = function (out, v) {
- out[0] = v.x;
- out[1] = v.y;
- out[2] = v.z;
- out[3] = v.w;
-
- return out;
-};
-
-/**
- * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
- *
- * @param {vec4} a The first vector.
- * @param {vec4} b The second vector.
- * @returns {Boolean} True if the vectors are equal, false otherwise.
- */
-vec4.exactEquals = function (a, b) {
- return a.x === b.x && a.y === b.y && a.z === b.z && a.w === b.w;
-};
-
-/**
- * Returns whether or not the vectors have approximately the same elements in the same position.
- *
- * @param {vec4} a The first vector.
- * @param {vec4} b The second vector.
- * @returns {Boolean} True if the vectors are equal, false otherwise.
- */
-vec4.equals = function (a, b) {
- var a0 = a.x, a1 = a.y, a2 = a.z, a3 = a.w;
- var b0 = b.x, b1 = b.y, b2 = b.z, b3 = b.w;
- return (Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
- Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
- Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)));
-};
-
-var _tmp$3 = new Array(9);
-
-var _mat3 = function _mat3(m00, m01, m02, m03, m04, m05, m06, m07, m08) {
- this.m00 = m00;
- this.m01 = m01;
- this.m02 = m02;
- this.m03 = m03;
- this.m04 = m04;
- this.m05 = m05;
- this.m06 = m06;
- this.m07 = m07;
- this.m08 = m08;
-};
-
-_mat3.prototype.toJSON = function toJSON () {
- _tmp$3[0] = this.m00;
- _tmp$3[1] = this.m01;
- _tmp$3[2] = this.m02;
- _tmp$3[3] = this.m03;
- _tmp$3[4] = this.m04;
- _tmp$3[5] = this.m05;
- _tmp$3[6] = this.m06;
- _tmp$3[7] = this.m07;
- _tmp$3[8] = this.m08;
-
- return _tmp$3;
-};
-
-/**
- * @class 3x3 Matrix
- * @name mat3
- *
- * NOTE: we use column-major matrix for all matrix calculation.
- *
- * This may lead to some confusion when referencing OpenGL documentation,
- * however, which represents out all matricies in column-major format.
- * This means that while in code a matrix may be typed out as:
- *
- * [1, 0, 0, 0,
- * 0, 1, 0, 0,
- * 0, 0, 1, 0,
- * x, y, z, 0]
- *
- * The same matrix in the [OpenGL documentation](https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTranslate.xml)
- * is written as:
- *
- * 1 0 0 x
- * 0 1 0 y
- * 0 0 1 z
- * 0 0 0 0
- *
- * Please rest assured, however, that they are the same thing!
- * This is not unique to glMatrix, either, as OpenGL developers have long been confused by the
- * apparent lack of consistency between the memory layout and the documentation.
- */
-var mat3 = {};
-
-/**
- * Creates a new identity mat3
- *
- * @returns {mat3} a new 3x3 matrix
- */
-mat3.create = function () {
- return new _mat3(
- 1, 0, 0,
- 0, 1, 0,
- 0, 0, 1
- );
-};
-
-/**
- * Create a new mat3 with the given values
- *
- * @param {Number} m00 Component in column 0, row 0 position (index 0)
- * @param {Number} m01 Component in column 0, row 1 position (index 1)
- * @param {Number} m02 Component in column 0, row 2 position (index 2)
- * @param {Number} m10 Component in column 1, row 0 position (index 3)
- * @param {Number} m11 Component in column 1, row 1 position (index 4)
- * @param {Number} m12 Component in column 1, row 2 position (index 5)
- * @param {Number} m20 Component in column 2, row 0 position (index 6)
- * @param {Number} m21 Component in column 2, row 1 position (index 7)
- * @param {Number} m22 Component in column 2, row 2 position (index 8)
- * @returns {mat3} A new mat3
- */
-mat3.new = function (m00, m01, m02, m10, m11, m12, m20, m21, m22) {
- return new _mat3(
- m00, m01, m02,
- m10, m11, m12,
- m20, m21, m22
- );
-};
-
-/**
- * Creates a new mat3 initialized with values from an existing matrix
- *
- * @param {mat3} a matrix to clone
- * @returns {mat3} a new 3x3 matrix
- */
-mat3.clone = function (a) {
- return new _mat3(
- a.m00, a.m01, a.m02,
- a.m03, a.m04, a.m05,
- a.m06, a.m07, a.m08
- );
-};
-
-/**
- * Copy the values from one mat3 to another
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the source matrix
- * @returns {mat3} out
- */
-mat3.copy = function (out, a) {
- out.m00 = a.m00;
- out.m01 = a.m01;
- out.m02 = a.m02;
- out.m03 = a.m03;
- out.m04 = a.m04;
- out.m05 = a.m05;
- out.m06 = a.m06;
- out.m07 = a.m07;
- out.m08 = a.m08;
- return out;
-};
-
-/**
- * Set the components of a mat3 to the given values
- *
- * @param {mat3} out the receiving matrix
- * @param {Number} m00 Component in column 0, row 0 position (index 0)
- * @param {Number} m01 Component in column 0, row 1 position (index 1)
- * @param {Number} m02 Component in column 0, row 2 position (index 2)
- * @param {Number} m10 Component in column 1, row 0 position (index 3)
- * @param {Number} m11 Component in column 1, row 1 position (index 4)
- * @param {Number} m12 Component in column 1, row 2 position (index 5)
- * @param {Number} m20 Component in column 2, row 0 position (index 6)
- * @param {Number} m21 Component in column 2, row 1 position (index 7)
- * @param {Number} m22 Component in column 2, row 2 position (index 8)
- * @returns {mat3} out
- */
-mat3.set = function (out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {
- out.m00 = m00;
- out.m01 = m01;
- out.m02 = m02;
- out.m03 = m10;
- out.m04 = m11;
- out.m05 = m12;
- out.m06 = m20;
- out.m07 = m21;
- out.m08 = m22;
- return out;
-};
-
-/**
- * Set a mat3 to the identity matrix
- *
- * @param {mat3} out the receiving matrix
- * @returns {mat3} out
- */
-mat3.identity = function (out) {
- out.m00 = 1;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 1;
- out.m05 = 0;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 1;
- return out;
-};
-
-/**
- * Transpose the values of a mat3
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the source matrix
- * @returns {mat3} out
- */
-mat3.transpose = function (out, a) {
- // If we are transposing ourselves we can skip a few steps but have to cache some values
- if (out === a) {
- var a01 = a.m01, a02 = a.m02, a12 = a.m05;
- out.m01 = a.m03;
- out.m02 = a.m06;
- out.m03 = a01;
- out.m05 = a.m07;
- out.m06 = a02;
- out.m07 = a12;
- } else {
- out.m00 = a.m00;
- out.m01 = a.m03;
- out.m02 = a.m06;
- out.m03 = a.m01;
- out.m04 = a.m04;
- out.m05 = a.m07;
- out.m06 = a.m02;
- out.m07 = a.m05;
- out.m08 = a.m08;
- }
-
- return out;
-};
-
-/**
- * Inverts a mat3
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the source matrix
- * @returns {mat3} out
- */
-mat3.invert = function (out, a) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02,
- a10 = a.m03, a11 = a.m04, a12 = a.m05,
- a20 = a.m06, a21 = a.m07, a22 = a.m08;
-
- var b01 = a22 * a11 - a12 * a21;
- var b11 = -a22 * a10 + a12 * a20;
- var b21 = a21 * a10 - a11 * a20;
-
- // Calculate the determinant
- var det = a00 * b01 + a01 * b11 + a02 * b21;
-
- if (!det) {
- return null;
- }
- det = 1.0 / det;
-
- out.m00 = b01 * det;
- out.m01 = (-a22 * a01 + a02 * a21) * det;
- out.m02 = (a12 * a01 - a02 * a11) * det;
- out.m03 = b11 * det;
- out.m04 = (a22 * a00 - a02 * a20) * det;
- out.m05 = (-a12 * a00 + a02 * a10) * det;
- out.m06 = b21 * det;
- out.m07 = (-a21 * a00 + a01 * a20) * det;
- out.m08 = (a11 * a00 - a01 * a10) * det;
- return out;
-};
-
-/**
- * Calculates the adjugate of a mat3
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the source matrix
- * @returns {mat3} out
- */
-mat3.adjoint = function (out, a) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02,
- a10 = a.m03, a11 = a.m04, a12 = a.m05,
- a20 = a.m06, a21 = a.m07, a22 = a.m08;
-
- out.m00 = (a11 * a22 - a12 * a21);
- out.m01 = (a02 * a21 - a01 * a22);
- out.m02 = (a01 * a12 - a02 * a11);
- out.m03 = (a12 * a20 - a10 * a22);
- out.m04 = (a00 * a22 - a02 * a20);
- out.m05 = (a02 * a10 - a00 * a12);
- out.m06 = (a10 * a21 - a11 * a20);
- out.m07 = (a01 * a20 - a00 * a21);
- out.m08 = (a00 * a11 - a01 * a10);
- return out;
-};
-
-/**
- * Calculates the determinant of a mat3
- *
- * @param {mat3} a the source matrix
- * @returns {Number} determinant of a
- */
-mat3.determinant = function (a) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02,
- a10 = a.m03, a11 = a.m04, a12 = a.m05,
- a20 = a.m06, a21 = a.m07, a22 = a.m08;
-
- return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
-};
-
-/**
- * Multiplies two mat3's
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the first operand
- * @param {mat3} b the second operand
- * @returns {mat3} out
- */
-mat3.multiply = function (out, a, b) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02,
- a10 = a.m03, a11 = a.m04, a12 = a.m05,
- a20 = a.m06, a21 = a.m07, a22 = a.m08;
-
- var b00 = b.m00, b01 = b.m01, b02 = b.m02;
- var b10 = b.m03, b11 = b.m04, b12 = b.m05;
- var b20 = b.m06, b21 = b.m07, b22 = b.m08;
-
- out.m00 = b00 * a00 + b01 * a10 + b02 * a20;
- out.m01 = b00 * a01 + b01 * a11 + b02 * a21;
- out.m02 = b00 * a02 + b01 * a12 + b02 * a22;
-
- out.m03 = b10 * a00 + b11 * a10 + b12 * a20;
- out.m04 = b10 * a01 + b11 * a11 + b12 * a21;
- out.m05 = b10 * a02 + b11 * a12 + b12 * a22;
-
- out.m06 = b20 * a00 + b21 * a10 + b22 * a20;
- out.m07 = b20 * a01 + b21 * a11 + b22 * a21;
- out.m08 = b20 * a02 + b21 * a12 + b22 * a22;
- return out;
-};
-
-/**
- * Alias for {@link mat3.multiply}
- * @function
- */
-mat3.mul = mat3.multiply;
-
-/**
- * Translate a mat3 by the given vector
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the matrix to translate
- * @param {vec2} v vector to translate by
- * @returns {mat3} out
- */
-mat3.translate = function (out, a, v) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02,
- a10 = a.m03, a11 = a.m04, a12 = a.m05,
- a20 = a.m06, a21 = a.m07, a22 = a.m08;
- var x = v.x, y = v.y;
-
- out.m00 = a00;
- out.m01 = a01;
- out.m02 = a02;
-
- out.m03 = a10;
- out.m04 = a11;
- out.m05 = a12;
-
- out.m06 = x * a00 + y * a10 + a20;
- out.m07 = x * a01 + y * a11 + a21;
- out.m08 = x * a02 + y * a12 + a22;
- return out;
-};
-
-/**
- * Rotates a mat3 by the given angle
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat3} out
- */
-mat3.rotate = function (out, a, rad) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02,
- a10 = a.m03, a11 = a.m04, a12 = a.m05,
- a20 = a.m06, a21 = a.m07, a22 = a.m08;
-
- var s = Math.sin(rad);
- var c = Math.cos(rad);
-
- out.m00 = c * a00 + s * a10;
- out.m01 = c * a01 + s * a11;
- out.m02 = c * a02 + s * a12;
-
- out.m03 = c * a10 - s * a00;
- out.m04 = c * a11 - s * a01;
- out.m05 = c * a12 - s * a02;
-
- out.m06 = a20;
- out.m07 = a21;
- out.m08 = a22;
- return out;
-};
-
-/**
- * Scales the mat3 by the dimensions in the given vec2
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the matrix to rotate
- * @param {vec2} v the vec2 to scale the matrix by
- * @returns {mat3} out
- **/
-mat3.scale = function (out, a, v) {
- var x = v.x, y = v.y;
-
- out.m00 = x * a.m00;
- out.m01 = x * a.m01;
- out.m02 = x * a.m02;
-
- out.m03 = y * a.m03;
- out.m04 = y * a.m04;
- out.m05 = y * a.m05;
-
- out.m06 = a.m06;
- out.m07 = a.m07;
- out.m08 = a.m08;
- return out;
-};
-
-/**
- * Copies the upper-left 3x3 values into the given mat3.
- *
- * @param {mat3} out the receiving 3x3 matrix
- * @param {mat4} a the source 4x4 matrix
- * @returns {mat3} out
- */
-mat3.fromMat4 = function (out, a) {
- out.m00 = a.m00;
- out.m01 = a.m01;
- out.m02 = a.m02;
- out.m03 = a.m04;
- out.m04 = a.m05;
- out.m05 = a.m06;
- out.m06 = a.m08;
- out.m07 = a.m09;
- out.m08 = a.m10;
- return out;
-};
-
-/**
- * Creates a matrix from a vector translation
- * This is equivalent to (but much faster than):
- *
- * mat3.identity(dest);
- * mat3.translate(dest, dest, vec);
- *
- * @param {mat3} out mat3 receiving operation result
- * @param {vec2} v Translation vector
- * @returns {mat3} out
- */
-mat3.fromTranslation = function (out, v) {
- out.m00 = 1;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 1;
- out.m05 = 0;
- out.m06 = v.x;
- out.m07 = v.y;
- out.m08 = 1;
- return out;
-};
-
-/**
- * Creates a matrix from a given angle
- * This is equivalent to (but much faster than):
- *
- * mat3.identity(dest);
- * mat3.rotate(dest, dest, rad);
- *
- * @param {mat3} out mat3 receiving operation result
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat3} out
- */
-mat3.fromRotation = function (out, rad) {
- var s = Math.sin(rad), c = Math.cos(rad);
-
- out.m00 = c;
- out.m01 = s;
- out.m02 = 0;
-
- out.m03 = -s;
- out.m04 = c;
- out.m05 = 0;
-
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 1;
- return out;
-};
-
-/**
- * Creates a matrix from a vector scaling
- * This is equivalent to (but much faster than):
- *
- * mat3.identity(dest);
- * mat3.scale(dest, dest, vec);
- *
- * @param {mat3} out mat3 receiving operation result
- * @param {vec2} v Scaling vector
- * @returns {mat3} out
- */
-mat3.fromScaling = function (out, v) {
- out.m00 = v.x;
- out.m01 = 0;
- out.m02 = 0;
-
- out.m03 = 0;
- out.m04 = v.y;
- out.m05 = 0;
-
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 1;
- return out;
-};
-
-/**
- * Copies the values from a mat2d into a mat3
- *
- * @param {mat3} out the receiving matrix
- * @param {mat2d} a the matrix to copy
- * @returns {mat3} out
- **/
-mat3.fromMat2d = function (out, a) {
- out.m00 = a.m00;
- out.m01 = a.m01;
- out.m02 = 0;
-
- out.m03 = a.m02;
- out.m04 = a.m03;
- out.m05 = 0;
-
- out.m06 = a.m04;
- out.m07 = a.m05;
- out.m08 = 1;
- return out;
-};
-
-/**
-* Calculates a 3x3 matrix from the given quaternion
-*
-* @param {mat3} out mat3 receiving operation result
-* @param {quat} q Quaternion to create matrix from
-*
-* @returns {mat3} out
-*/
-mat3.fromQuat = function (out, q) {
- var x = q.x, y = q.y, z = q.z, w = q.w;
- var x2 = x + x;
- var y2 = y + y;
- var z2 = z + z;
-
- var xx = x * x2;
- var yx = y * x2;
- var yy = y * y2;
- var zx = z * x2;
- var zy = z * y2;
- var zz = z * z2;
- var wx = w * x2;
- var wy = w * y2;
- var wz = w * z2;
-
- out.m00 = 1 - yy - zz;
- out.m03 = yx - wz;
- out.m06 = zx + wy;
-
- out.m01 = yx + wz;
- out.m04 = 1 - xx - zz;
- out.m07 = zy - wx;
-
- out.m02 = zx - wy;
- out.m05 = zy + wx;
- out.m08 = 1 - xx - yy;
-
- return out;
-};
-
-/**
-* Calculates a 3x3 matrix from view direction and up direction
-*
-* @param {mat3} out mat3 receiving operation result
-* @param {vec3} view view direction (must be normalized)
-* @param {vec3} [up] up direction, default is (0,1,0) (must be normalized)
-*
-* @returns {mat3} out
-*/
-mat3.fromViewUp = (function () {
- var default_up = vec3.new(0, 1, 0);
- var x = vec3.create();
- var y = vec3.create();
-
- return function (out, view, up) {
- if (vec3.sqrLen(view) < EPSILON * EPSILON) {
- mat3.identity(out);
- return out;
- }
-
- up = up || default_up;
- vec3.cross(x, up, view);
-
- if (vec3.sqrLen(x) < EPSILON * EPSILON) {
- mat3.identity(out);
- return out;
- }
-
- vec3.cross(y, view, x);
- mat3.set(out,
- x.x, x.y, x.z,
- y.x, y.y, y.z,
- view.x, view.y, view.z
- );
-
- return out;
- };
-})();
-
-/**
-* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
-*
-* @param {mat3} out mat3 receiving operation result
-* @param {mat4} a Mat4 to derive the normal matrix from
-*
-* @returns {mat3} out
-*/
-mat3.normalFromMat4 = function (out, a) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02, a03 = a.m03,
- a10 = a.m04, a11 = a.m05, a12 = a.m06, a13 = a.m07,
- a20 = a.m08, a21 = a.m09, a22 = a.m10, a23 = a.m11,
- a30 = a.m12, a31 = a.m13, a32 = a.m14, a33 = a.m15;
-
- var b00 = a00 * a11 - a01 * a10;
- var b01 = a00 * a12 - a02 * a10;
- var b02 = a00 * a13 - a03 * a10;
- var b03 = a01 * a12 - a02 * a11;
- var b04 = a01 * a13 - a03 * a11;
- var b05 = a02 * a13 - a03 * a12;
- var b06 = a20 * a31 - a21 * a30;
- var b07 = a20 * a32 - a22 * a30;
- var b08 = a20 * a33 - a23 * a30;
- var b09 = a21 * a32 - a22 * a31;
- var b10 = a21 * a33 - a23 * a31;
- var b11 = a22 * a33 - a23 * a32;
-
- // Calculate the determinant
- var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
-
- if (!det) {
- return null;
- }
- det = 1.0 / det;
-
- out.m00 = (a11 * b11 - a12 * b10 + a13 * b09) * det;
- out.m01 = (a12 * b08 - a10 * b11 - a13 * b07) * det;
- out.m02 = (a10 * b10 - a11 * b08 + a13 * b06) * det;
-
- out.m03 = (a02 * b10 - a01 * b11 - a03 * b09) * det;
- out.m04 = (a00 * b11 - a02 * b08 + a03 * b07) * det;
- out.m05 = (a01 * b08 - a00 * b10 - a03 * b06) * det;
-
- out.m06 = (a31 * b05 - a32 * b04 + a33 * b03) * det;
- out.m07 = (a32 * b02 - a30 * b05 - a33 * b01) * det;
- out.m08 = (a30 * b04 - a31 * b02 + a33 * b00) * det;
-
- return out;
-};
-
-/**
- * Returns a string representation of a mat3
- *
- * @param {mat3} a matrix to represent as a string
- * @returns {String} string representation of the matrix
- */
-mat3.str = function (a) {
- return ("mat3(" + (a.m00) + ", " + (a.m01) + ", " + (a.m02) + ", " + (a.m03) + ", " + (a.m04) + ", " + (a.m05) + ", " + (a.m06) + ", " + (a.m07) + ", " + (a.m08) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {mat3} m
- * @returns {array}
- */
-mat3.array = function (out, m) {
- out[0] = m.m00;
- out[1] = m.m01;
- out[2] = m.m02;
- out[3] = m.m03;
- out[4] = m.m04;
- out[5] = m.m05;
- out[6] = m.m06;
- out[7] = m.m07;
- out[8] = m.m08;
-
- return out;
-};
-
-/**
- * Returns Frobenius norm of a mat3
- *
- * @param {mat3} a the matrix to calculate Frobenius norm of
- * @returns {Number} Frobenius norm
- */
-mat3.frob = function (a) {
- return (Math.sqrt(Math.pow(a.m00, 2) + Math.pow(a.m01, 2) + Math.pow(a.m02, 2) + Math.pow(a.m03, 2) + Math.pow(a.m04, 2) + Math.pow(a.m05, 2) + Math.pow(a.m06, 2) + Math.pow(a.m07, 2) + Math.pow(a.m08, 2)));
-};
-
-/**
- * Adds two mat3's
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the first operand
- * @param {mat3} b the second operand
- * @returns {mat3} out
- */
-mat3.add = function (out, a, b) {
- out.m00 = a.m00 + b.m00;
- out.m01 = a.m01 + b.m01;
- out.m02 = a.m02 + b.m02;
- out.m03 = a.m03 + b.m03;
- out.m04 = a.m04 + b.m04;
- out.m05 = a.m05 + b.m05;
- out.m06 = a.m06 + b.m06;
- out.m07 = a.m07 + b.m07;
- out.m08 = a.m08 + b.m08;
- return out;
-};
-
-/**
- * Subtracts matrix b from matrix a
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the first operand
- * @param {mat3} b the second operand
- * @returns {mat3} out
- */
-mat3.subtract = function (out, a, b) {
- out.m00 = a.m00 - b.m00;
- out.m01 = a.m01 - b.m01;
- out.m02 = a.m02 - b.m02;
- out.m03 = a.m03 - b.m03;
- out.m04 = a.m04 - b.m04;
- out.m05 = a.m05 - b.m05;
- out.m06 = a.m06 - b.m06;
- out.m07 = a.m07 - b.m07;
- out.m08 = a.m08 - b.m08;
- return out;
-};
-
-/**
- * Alias for {@link mat3.subtract}
- * @function
- */
-mat3.sub = mat3.subtract;
-
-/**
- * Multiply each element of the matrix by a scalar.
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the matrix to scale
- * @param {Number} b amount to scale the matrix's elements by
- * @returns {mat3} out
- */
-mat3.multiplyScalar = function (out, a, b) {
- out.m00 = a.m00 * b;
- out.m01 = a.m01 * b;
- out.m02 = a.m02 * b;
- out.m03 = a.m03 * b;
- out.m04 = a.m04 * b;
- out.m05 = a.m05 * b;
- out.m06 = a.m06 * b;
- out.m07 = a.m07 * b;
- out.m08 = a.m08 * b;
- return out;
-};
-
-/**
- * Adds two mat3's after multiplying each element of the second operand by a scalar value.
- *
- * @param {mat3} out the receiving vector
- * @param {mat3} a the first operand
- * @param {mat3} b the second operand
- * @param {Number} scale the amount to scale b's elements by before adding
- * @returns {mat3} out
- */
-mat3.multiplyScalarAndAdd = function (out, a, b, scale) {
- out.m00 = a.m00 + (b.m00 * scale);
- out.m01 = a.m01 + (b.m01 * scale);
- out.m02 = a.m02 + (b.m02 * scale);
- out.m03 = a.m03 + (b.m03 * scale);
- out.m04 = a.m04 + (b.m04 * scale);
- out.m05 = a.m05 + (b.m05 * scale);
- out.m06 = a.m06 + (b.m06 * scale);
- out.m07 = a.m07 + (b.m07 * scale);
- out.m08 = a.m08 + (b.m08 * scale);
- return out;
-};
-
-/**
- * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
- *
- * @param {mat3} a The first matrix.
- * @param {mat3} b The second matrix.
- * @returns {Boolean} True if the matrices are equal, false otherwise.
- */
-mat3.exactEquals = function (a, b) {
- return a.m00 === b.m00 && a.m01 === b.m01 && a.m02 === b.m02 &&
- a.m03 === b.m03 && a.m04 === b.m04 && a.m05 === b.m05 &&
- a.m06 === b.m06 && a.m07 === b.m07 && a.m08 === b.m08;
-};
-
-/**
- * Returns whether or not the matrices have approximately the same elements in the same position.
- *
- * @param {mat3} a The first matrix.
- * @param {mat3} b The second matrix.
- * @returns {Boolean} True if the matrices are equal, false otherwise.
- */
-mat3.equals = function (a, b) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03, a4 = a.m04, a5 = a.m05, a6 = a.m06, a7 = a.m07, a8 = a.m08;
- var b0 = b.m00, b1 = b.m01, b2 = b.m02, b3 = b.m03, b4 = b.m04, b5 = b.m05, b6 = b.m06, b7 = b.m07, b8 = b.m08;
- return (
- Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
- Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
- Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&
- Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&
- Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&
- Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&
- Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) &&
- Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8))
- );
-};
-
-var _tmp$4 = new Array(4);
-
-var _quat = function _quat(x, y, z, w) {
- this.x = x;
- this.y = y;
- this.z = z;
- this.w = w;
-};
-
-_quat.prototype.toJSON = function toJSON () {
- _tmp$4[0] = this.x;
- _tmp$4[1] = this.y;
- _tmp$4[2] = this.z;
- _tmp$4[3] = this.w;
-
- return _tmp$4;
-};
-
-/**
- * @class Quaternion
- * @name quat
- */
-var quat = {};
-
-/**
- * Creates a new identity quat
- *
- * @returns {quat} a new quaternion
- */
-quat.create = function () {
- return new _quat(0, 0, 0, 1);
-};
-
-/**
- * Creates a new quat initialized with the given values
- *
- * @param {Number} x X component
- * @param {Number} y Y component
- * @param {Number} z Z component
- * @param {Number} w W component
- * @returns {quat} a new quaternion
- * @function
- */
-quat.new = function (x, y, z, w) {
- return new _quat(x, y, z, w);
-};
-
-/**
- * Creates a new quat initialized with values from an existing quaternion
- *
- * @param {quat} a quaternion to clone
- * @returns {quat} a new quaternion
- * @function
- */
-quat.clone = function (a) {
- return new _quat(a.x, a.y, a.z, a.w);
-};
-
-/**
- * Copy the values from one quat to another
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a the source quaternion
- * @returns {quat} out
- * @function
- */
-quat.copy = vec4.copy;
-
-/**
- * Set the components of a quat to the given values
- *
- * @param {quat} out the receiving quaternion
- * @param {Number} x X component
- * @param {Number} y Y component
- * @param {Number} z Z component
- * @param {Number} w W component
- * @returns {quat} out
- * @function
- */
-quat.set = vec4.set;
-
-/**
- * Set a quat to the identity quaternion
- *
- * @param {quat} out the receiving quaternion
- * @returns {quat} out
- */
-quat.identity = function (out) {
- out.x = 0;
- out.y = 0;
- out.z = 0;
- out.w = 1;
- return out;
-};
-
-/**
- * Sets a quaternion to represent the shortest rotation from one
- * vector to another.
- *
- * Both vectors are assumed to be unit length.
- *
- * @param {quat} out the receiving quaternion.
- * @param {vec3} a the initial vector
- * @param {vec3} b the destination vector
- * @returns {quat} out
- */
-quat.rotationTo = (function () {
- var tmpvec3 = vec3.create();
- var xUnitVec3 = vec3.new(1, 0, 0);
- var yUnitVec3 = vec3.new(0, 1, 0);
-
- return function (out, a, b) {
- var dot = vec3.dot(a, b);
- if (dot < -0.999999) {
- vec3.cross(tmpvec3, xUnitVec3, a);
- if (vec3.length(tmpvec3) < 0.000001) {
- vec3.cross(tmpvec3, yUnitVec3, a);
- }
- vec3.normalize(tmpvec3, tmpvec3);
- quat.fromAxisAngle(out, tmpvec3, Math.PI);
- return out;
- } else if (dot > 0.999999) {
- out.x = 0;
- out.y = 0;
- out.z = 0;
- out.w = 1;
- return out;
- } else {
- vec3.cross(tmpvec3, a, b);
- out.x = tmpvec3.x;
- out.y = tmpvec3.y;
- out.z = tmpvec3.z;
- out.w = 1 + dot;
- return quat.normalize(out, out);
- }
- };
-})();
-
-/**
- * Gets the rotation axis and angle for a given
- * quaternion. If a quaternion is created with
- * fromAxisAngle, this method will return the same
- * values as providied in the original parameter list
- * OR functionally equivalent values.
- * Example: The quaternion formed by axis [0, 0, 1] and
- * angle -90 is the same as the quaternion formed by
- * [0, 0, 1] and 270. This method favors the latter.
- * @param {vec3} out_axis Vector receiving the axis of rotation
- * @param {quat} q Quaternion to be decomposed
- * @return {Number} Angle, in radians, of the rotation
- */
-quat.getAxisAngle = function (out_axis, q) {
- var rad = Math.acos(q.w) * 2.0;
- var s = Math.sin(rad / 2.0);
- if (s != 0.0) {
- out_axis.x = q.x / s;
- out_axis.y = q.y / s;
- out_axis.z = q.z / s;
- } else {
- // If s is zero, return any axis (no rotation - axis does not matter)
- out_axis.x = 1;
- out_axis.y = 0;
- out_axis.z = 0;
- }
- return rad;
-};
-
-/**
- * Multiplies two quat's
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a the first operand
- * @param {quat} b the second operand
- * @returns {quat} out
- */
-quat.multiply = function (out, a, b) {
- var ax = a.x, ay = a.y, az = a.z, aw = a.w,
- bx = b.x, by = b.y, bz = b.z, bw = b.w;
-
- out.x = ax * bw + aw * bx + ay * bz - az * by;
- out.y = ay * bw + aw * by + az * bx - ax * bz;
- out.z = az * bw + aw * bz + ax * by - ay * bx;
- out.w = aw * bw - ax * bx - ay * by - az * bz;
- return out;
-};
-
-/**
- * Alias for {@link quat.multiply}
- * @function
- */
-quat.mul = quat.multiply;
-
-/**
- * Scales a quat by a scalar number
- *
- * @param {quat} out the receiving vector
- * @param {quat} a the vector to scale
- * @param {Number} b amount to scale the vector by
- * @returns {quat} out
- * @function
- */
-quat.scale = vec4.scale;
-
-/**
- * Rotates a quaternion by the given angle about the X axis
- *
- * @param {quat} out quat receiving operation result
- * @param {quat} a quat to rotate
- * @param {number} rad angle (in radians) to rotate
- * @returns {quat} out
- */
-quat.rotateX = function (out, a, rad) {
- rad *= 0.5;
-
- var ax = a.x, ay = a.y, az = a.z, aw = a.w,
- bx = Math.sin(rad), bw = Math.cos(rad);
-
- out.x = ax * bw + aw * bx;
- out.y = ay * bw + az * bx;
- out.z = az * bw - ay * bx;
- out.w = aw * bw - ax * bx;
- return out;
-};
-
-/**
- * Rotates a quaternion by the given angle about the Y axis
- *
- * @param {quat} out quat receiving operation result
- * @param {quat} a quat to rotate
- * @param {number} rad angle (in radians) to rotate
- * @returns {quat} out
- */
-quat.rotateY = function (out, a, rad) {
- rad *= 0.5;
-
- var ax = a.x, ay = a.y, az = a.z, aw = a.w,
- by = Math.sin(rad), bw = Math.cos(rad);
-
- out.x = ax * bw - az * by;
- out.y = ay * bw + aw * by;
- out.z = az * bw + ax * by;
- out.w = aw * bw - ay * by;
- return out;
-};
-
-/**
- * Rotates a quaternion by the given angle about the Z axis
- *
- * @param {quat} out quat receiving operation result
- * @param {quat} a quat to rotate
- * @param {number} rad angle (in radians) to rotate
- * @returns {quat} out
- */
-quat.rotateZ = function (out, a, rad) {
- rad *= 0.5;
-
- var ax = a.x, ay = a.y, az = a.z, aw = a.w,
- bz = Math.sin(rad), bw = Math.cos(rad);
-
- out.x = ax * bw + ay * bz;
- out.y = ay * bw - ax * bz;
- out.z = az * bw + aw * bz;
- out.w = aw * bw - az * bz;
- return out;
-};
-
-/**
- * Rotates a quaternion by the given angle about the axis in world space
- *
- * @param {quat} out quat receiving operation result
- * @param {quat} rot quat to rotate
- * @param {vec3} axis the axis around which to rotate in world space
- * @param {number} rad angle (in radians) to rotate
- * @returns {quat} out
- */
-quat.rotateAround = (function () {
- var v3_tmp = vec3.create();
- var q_tmp = quat.create();
-
- return function (out, rot, axis, rad) {
- // get inv-axis (local to rot)
- quat.invert(q_tmp, rot);
- vec3.transformQuat(v3_tmp, axis, q_tmp);
- // rotate by inv-axis
- quat.fromAxisAngle(q_tmp, v3_tmp, rad);
- quat.mul(out, rot, q_tmp);
-
- return out;
- };
-})();
-
-/**
- * Rotates a quaternion by the given angle about the axis in local space
- *
- * @param {quat} out quat receiving operation result
- * @param {quat} rot quat to rotate
- * @param {vec3} axis the axis around which to rotate in local space
- * @param {number} rad angle (in radians) to rotate
- * @returns {quat} out
- */
-quat.rotateAroundLocal = (function () {
- var q_tmp = quat.create();
-
- return function (out, rot, axis, rad) {
- quat.fromAxisAngle(q_tmp, axis, rad);
- quat.mul(out, rot, q_tmp);
-
- return out;
- };
-})();
-
-/**
- * Calculates the W component of a quat from the X, Y, and Z components.
- * Assumes that quaternion is 1 unit in length.
- * Any existing W component will be ignored.
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a quat to calculate W component of
- * @returns {quat} out
- */
-quat.calculateW = function (out, a) {
- var x = a.x, y = a.y, z = a.z;
-
- out.x = x;
- out.y = y;
- out.z = z;
- out.w = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
- return out;
-};
-
-/**
- * Calculates the dot product of two quat's
- *
- * @param {quat} a the first operand
- * @param {quat} b the second operand
- * @returns {Number} dot product of a and b
- * @function
- */
-quat.dot = vec4.dot;
-
-/**
- * Performs a linear interpolation between two quat's
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a the first operand
- * @param {quat} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {quat} out
- * @function
- */
-quat.lerp = vec4.lerp;
-
-/**
- * Performs a spherical linear interpolation between two quat
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a the first operand
- * @param {quat} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {quat} out
- */
-quat.slerp = function (out, a, b, t) {
- // benchmarks:
- // http://jsperf.com/quaternion-slerp-implementations
-
- var ax = a.x, ay = a.y, az = a.z, aw = a.w,
- bx = b.x, by = b.y, bz = b.z, bw = b.w;
-
- var omega, cosom, sinom, scale0, scale1;
-
- // calc cosine
- cosom = ax * bx + ay * by + az * bz + aw * bw;
- // adjust signs (if necessary)
- if (cosom < 0.0) {
- cosom = -cosom;
- bx = - bx;
- by = - by;
- bz = - bz;
- bw = - bw;
- }
- // calculate coefficients
- if ((1.0 - cosom) > 0.000001) {
- // standard case (slerp)
- omega = Math.acos(cosom);
- sinom = Math.sin(omega);
- scale0 = Math.sin((1.0 - t) * omega) / sinom;
- scale1 = Math.sin(t * omega) / sinom;
- } else {
- // "from" and "to" quaternions are very close
- // ... so we can do a linear interpolation
- scale0 = 1.0 - t;
- scale1 = t;
- }
- // calculate final values
- out.x = scale0 * ax + scale1 * bx;
- out.y = scale0 * ay + scale1 * by;
- out.z = scale0 * az + scale1 * bz;
- out.w = scale0 * aw + scale1 * bw;
-
- return out;
-};
-
-/**
- * Performs a spherical linear interpolation with two control points
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a the first operand
- * @param {quat} b the second operand
- * @param {quat} c the third operand
- * @param {quat} d the fourth operand
- * @param {Number} t interpolation amount
- * @returns {quat} out
- */
-quat.sqlerp = (function () {
- var temp1 = quat.create();
- var temp2 = quat.create();
-
- return function (out, a, b, c, d, t) {
- quat.slerp(temp1, a, d, t);
- quat.slerp(temp2, b, c, t);
- quat.slerp(out, temp1, temp2, 2 * t * (1 - t));
-
- return out;
- };
-}());
-
-/**
- * Calculates the inverse of a quat
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a quat to calculate inverse of
- * @returns {quat} out
- */
-quat.invert = function (out, a) {
- var a0 = a.x, a1 = a.y, a2 = a.z, a3 = a.w;
- var dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
- var invDot = dot ? 1.0 / dot : 0;
-
- // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
-
- out.x = -a0 * invDot;
- out.y = -a1 * invDot;
- out.z = -a2 * invDot;
- out.w = a3 * invDot;
- return out;
-};
-
-/**
- * Calculates the conjugate of a quat
- * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a quat to calculate conjugate of
- * @returns {quat} out
- */
-quat.conjugate = function (out, a) {
- out.x = -a.x;
- out.y = -a.y;
- out.z = -a.z;
- out.w = a.w;
- return out;
-};
-
-/**
- * Calculates the length of a quat
- *
- * @param {quat} a vector to calculate length of
- * @returns {Number} length of a
- * @function
- */
-quat.length = vec4.length;
-
-/**
- * Alias for {@link quat.length}
- * @function
- */
-quat.len = quat.length;
-
-/**
- * Calculates the squared length of a quat
- *
- * @param {quat} a vector to calculate squared length of
- * @returns {Number} squared length of a
- * @function
- */
-quat.squaredLength = vec4.squaredLength;
-
-/**
- * Alias for {@link quat.squaredLength}
- * @function
- */
-quat.sqrLen = quat.squaredLength;
-
-/**
- * Normalize a quat
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a quaternion to normalize
- * @returns {quat} out
- * @function
- */
-quat.normalize = vec4.normalize;
-
-/**
- * Sets the specified quaternion with values corresponding to the given
- * axes. Each axis is a vec3 and is expected to be unit length and
- * perpendicular to all other specified axes.
- *
- * @param {vec3} xAxis the vector representing the local "right" direction
- * @param {vec3} yAxis the vector representing the local "up" direction
- * @param {vec3} zAxis the vector representing the viewing direction
- * @returns {quat} out
- */
-quat.fromAxes = (function () {
- var matr = mat3.create();
-
- return function (out, xAxis, yAxis, zAxis) {
- mat3.set(
- matr,
- xAxis.x, xAxis.y, xAxis.z,
- yAxis.x, yAxis.y, yAxis.z,
- zAxis.x, zAxis.y, zAxis.z
- );
- return quat.normalize(out, quat.fromMat3(out, matr));
- };
-})();
-
-/**
-* Calculates a quaternion from view direction and up direction
-*
-* @param {quat} out mat3 receiving operation result
-* @param {vec3} view view direction (must be normalized)
-* @param {vec3} [up] up direction, default is (0,1,0) (must be normalized)
-*
-* @returns {quat} out
-*/
-quat.fromViewUp = (function () {
- var matr = mat3.create();
-
- return function (out, view, up) {
- mat3.fromViewUp(matr, view, up);
- if (!matr) {
- return null;
- }
-
- return quat.normalize(out, quat.fromMat3(out, matr));
- };
-})();
-
-/**
- * Sets a quat from the given angle and rotation axis,
- * then returns it.
- *
- * @param {quat} out the receiving quaternion
- * @param {vec3} axis the axis around which to rotate
- * @param {Number} rad the angle in radians
- * @returns {quat} out
- **/
-quat.fromAxisAngle = function (out, axis, rad) {
- rad = rad * 0.5;
- var s = Math.sin(rad);
- out.x = s * axis.x;
- out.y = s * axis.y;
- out.z = s * axis.z;
- out.w = Math.cos(rad);
- return out;
-};
-
-/**
- * Creates a quaternion from the given 3x3 rotation matrix.
- *
- * NOTE: The resultant quaternion is not normalized, so you should be sure
- * to renormalize the quaternion yourself where necessary.
- *
- * @param {quat} out the receiving quaternion
- * @param {mat3} m rotation matrix
- * @returns {quat} out
- * @function
- */
-quat.fromMat3 = function (out, m) {
- // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
-
- var m00 = m.m00, m01 = m.m03, m02 = m.m06,
- m10 = m.m01, m11 = m.m04, m12 = m.m07,
- m20 = m.m02, m21 = m.m05, m22 = m.m08;
-
- var trace = m00 + m11 + m22;
-
- if (trace > 0) {
- var s = 0.5 / Math.sqrt(trace + 1.0);
-
- out.w = 0.25 / s;
- out.x = (m21 - m12) * s;
- out.y = (m02 - m20) * s;
- out.z = (m10 - m01) * s;
-
- } else if ((m00 > m11) && (m00 > m22)) {
- var s$1 = 2.0 * Math.sqrt(1.0 + m00 - m11 - m22);
-
- out.w = (m21 - m12) / s$1;
- out.x = 0.25 * s$1;
- out.y = (m01 + m10) / s$1;
- out.z = (m02 + m20) / s$1;
-
- } else if (m11 > m22) {
- var s$2 = 2.0 * Math.sqrt(1.0 + m11 - m00 - m22);
-
- out.w = (m02 - m20) / s$2;
- out.x = (m01 + m10) / s$2;
- out.y = 0.25 * s$2;
- out.z = (m12 + m21) / s$2;
-
- } else {
- var s$3 = 2.0 * Math.sqrt(1.0 + m22 - m00 - m11);
-
- out.w = (m10 - m01) / s$3;
- out.x = (m02 + m20) / s$3;
- out.y = (m12 + m21) / s$3;
- out.z = 0.25 * s$3;
- }
-
- return out;
-};
-
-/**
- * Creates a quaternion from the given euler angle x, y, z.
- *
- * @param {quat} out the receiving quaternion
- * @param {x} Angle to rotate around X axis in degrees.
- * @param {y} Angle to rotate around Y axis in degrees.
- * @param {z} Angle to rotate around Z axis in degrees.
- * @returns {quat} out
- * @function
- */
-quat.fromEuler = function (out, x, y, z) {
- var halfToRad = 0.5 * Math.PI / 180.0;
- x *= halfToRad;
- y *= halfToRad;
- z *= halfToRad;
-
- var sx = Math.sin(x);
- var cx = Math.cos(x);
- var sy = Math.sin(y);
- var cy = Math.cos(y);
- var sz = Math.sin(z);
- var cz = Math.cos(z);
-
- out.x = sx * cy * cz - cx * sy * sz;
- out.y = cx * sy * cz + sx * cy * sz;
- out.z = cx * cy * sz - sx * sy * cz;
- out.w = cx * cy * cz + sx * sy * sz;
-
- return out;
-};
-
-/**
- * Returns a string representation of a quatenion
- *
- * @param {quat} a vector to represent as a string
- * @returns {String} string representation of the vector
- */
-quat.str = function (a) {
- return ("quat(" + (a.x) + ", " + (a.y) + ", " + (a.z) + ", " + (a.w) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {quat} q
- * @returns {array}
- */
-quat.array = function (out, q) {
- out[0] = q.x;
- out[1] = q.y;
- out[2] = q.z;
- out[3] = q.w;
-
- return out;
-};
-
-/**
- * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)
- *
- * @param {quat} a The first quaternion.
- * @param {quat} b The second quaternion.
- * @returns {Boolean} True if the vectors are equal, false otherwise.
- */
-quat.exactEquals = vec4.exactEquals;
-
-/**
- * Returns whether or not the quaternions have approximately the same elements in the same position.
- *
- * @param {quat} a The first vector.
- * @param {quat} b The second vector.
- * @returns {Boolean} True if the vectors are equal, false otherwise.
- */
-quat.equals = vec4.equals;
-
-var _tmp$5 = new Array(4);
-
-var _mat2 = function _mat2(m00, m01, m02, m03) {
- this.m00 = m00;
- this.m01 = m01;
- this.m02 = m02;
- this.m03 = m03;
-};
-
-_mat2.prototype.toJSON = function toJSON () {
- _tmp$5[0] = this.m00;
- _tmp$5[1] = this.m01;
- _tmp$5[2] = this.m02;
- _tmp$5[3] = this.m03;
-
- return _tmp$5;
-};
-
-/**
- * @class 2x2 Matrix
- * @name mat2
- */
-var mat2 = {};
-
-/**
- * Creates a new identity mat2
- *
- * @returns {mat2} a new 2x2 matrix
- */
-mat2.create = function() {
- return new _mat2(1, 0, 0, 1);
-};
-
-/**
- * Create a new mat2 with the given values
- *
- * @param {Number} m00 Component in column 0, row 0 position (index 0)
- * @param {Number} m01 Component in column 0, row 1 position (index 1)
- * @param {Number} m10 Component in column 1, row 0 position (index 2)
- * @param {Number} m11 Component in column 1, row 1 position (index 3)
- * @returns {mat2} out A new 2x2 matrix
- */
-mat2.new = function (m00, m01, m10, m11) {
- return new _mat2(m00, m01, m10, m11);
-};
-
-/**
- * Creates a new mat2 initialized with values from an existing matrix
- *
- * @param {mat2} a matrix to clone
- * @returns {mat2} a new 2x2 matrix
- */
-mat2.clone = function (a) {
- return new _mat2(a.m00, a.m01, a.m02, a.m03);
-};
-
-/**
- * Copy the values from one mat2 to another
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the source matrix
- * @returns {mat2} out
- */
-mat2.copy = function (out, a) {
- out.m00 = a.m00;
- out.m01 = a.m01;
- out.m02 = a.m02;
- out.m03 = a.m03;
- return out;
-};
-
-/**
- * Set a mat2 to the identity matrix
- *
- * @param {mat2} out the receiving matrix
- * @returns {mat2} out
- */
-mat2.identity = function (out) {
- out.m00 = 1;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 1;
- return out;
-};
-
-/**
- * Set the components of a mat2 to the given values
- *
- * @param {mat2} out the receiving matrix
- * @param {Number} m00 Component in column 0, row 0 position (index 0)
- * @param {Number} m01 Component in column 0, row 1 position (index 1)
- * @param {Number} m10 Component in column 1, row 0 position (index 2)
- * @param {Number} m11 Component in column 1, row 1 position (index 3)
- * @returns {mat2} out
- */
-mat2.set = function (out, m00, m01, m10, m11) {
- out.m00 = m00;
- out.m01 = m01;
- out.m02 = m10;
- out.m03 = m11;
- return out;
-};
-
-
-/**
- * Transpose the values of a mat2
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the source matrix
- * @returns {mat2} out
- */
-mat2.transpose = function (out, a) {
- // If we are transposing ourselves we can skip a few steps but have to cache some values
- if (out === a) {
- var a1 = a.m01;
- out.m01 = a.m02;
- out.m02 = a1;
- } else {
- out.m00 = a.m00;
- out.m01 = a.m02;
- out.m02 = a.m01;
- out.m03 = a.m03;
- }
-
- return out;
-};
-
-/**
- * Inverts a mat2
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the source matrix
- * @returns {mat2} out
- */
-mat2.invert = function (out, a) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03;
-
- // Calculate the determinant
- var det = a0 * a3 - a2 * a1;
-
- if (!det) {
- return null;
- }
- det = 1.0 / det;
-
- out.m00 = a3 * det;
- out.m01 = -a1 * det;
- out.m02 = -a2 * det;
- out.m03 = a0 * det;
-
- return out;
-};
-
-/**
- * Calculates the adjugate of a mat2
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the source matrix
- * @returns {mat2} out
- */
-mat2.adjoint = function (out, a) {
- // Caching this value is nessecary if out == a
- var a0 = a.m00;
- out.m00 = a.m03;
- out.m01 = -a.m01;
- out.m02 = -a.m02;
- out.m03 = a0;
-
- return out;
-};
-
-/**
- * Calculates the determinant of a mat2
- *
- * @param {mat2} a the source matrix
- * @returns {Number} determinant of a
- */
-mat2.determinant = function (a) {
- return a.m00 * a.m03 - a.m02 * a.m01;
-};
-
-/**
- * Multiplies two mat2's
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the first operand
- * @param {mat2} b the second operand
- * @returns {mat2} out
- */
-mat2.multiply = function (out, a, b) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03;
- var b0 = b.m00, b1 = b.m01, b2 = b.m02, b3 = b.m03;
- out.m00 = a0 * b0 + a2 * b1;
- out.m01 = a1 * b0 + a3 * b1;
- out.m02 = a0 * b2 + a2 * b3;
- out.m03 = a1 * b2 + a3 * b3;
- return out;
-};
-
-/**
- * Alias for {@link mat2.multiply}
- * @function
- */
-mat2.mul = mat2.multiply;
-
-/**
- * Rotates a mat2 by the given angle
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat2} out
- */
-mat2.rotate = function (out, a, rad) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03,
- s = Math.sin(rad),
- c = Math.cos(rad);
- out.m00 = a0 * c + a2 * s;
- out.m01 = a1 * c + a3 * s;
- out.m02 = a0 * -s + a2 * c;
- out.m03 = a1 * -s + a3 * c;
- return out;
-};
-
-/**
- * Scales the mat2 by the dimensions in the given vec2
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the matrix to rotate
- * @param {vec2} v the vec2 to scale the matrix by
- * @returns {mat2} out
- **/
-mat2.scale = function (out, a, v) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03,
- v0 = v.x, v1 = v.y;
- out.m00 = a0 * v0;
- out.m01 = a1 * v0;
- out.m02 = a2 * v1;
- out.m03 = a3 * v1;
- return out;
-};
-
-/**
- * Creates a matrix from a given angle
- * This is equivalent to (but much faster than):
- *
- * mat2.identity(dest);
- * mat2.rotate(dest, dest, rad);
- *
- * @param {mat2} out mat2 receiving operation result
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat2} out
- */
-mat2.fromRotation = function (out, rad) {
- var s = Math.sin(rad),
- c = Math.cos(rad);
- out.m00 = c;
- out.m01 = s;
- out.m02 = -s;
- out.m03 = c;
- return out;
-};
-
-/**
- * Creates a matrix from a vector scaling
- * This is equivalent to (but much faster than):
- *
- * mat2.identity(dest);
- * mat2.scale(dest, dest, vec);
- *
- * @param {mat2} out mat2 receiving operation result
- * @param {vec2} v Scaling vector
- * @returns {mat2} out
- */
-mat2.fromScaling = function (out, v) {
- out.m00 = v.x;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = v.y;
- return out;
-};
-
-/**
- * Returns a string representation of a mat2
- *
- * @param {mat2} a matrix to represent as a string
- * @returns {String} string representation of the matrix
- */
-mat2.str = function (a) {
- return ("mat2(" + (a.m00) + ", " + (a.m01) + ", " + (a.m02) + ", " + (a.m03) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {mat2} m
- * @returns {array}
- */
-mat2.array = function (out, m) {
- out[0] = m.m00;
- out[1] = m.m01;
- out[2] = m.m02;
- out[3] = m.m03;
-
- return out;
-};
-
-/**
- * Returns Frobenius norm of a mat2
- *
- * @param {mat2} a the matrix to calculate Frobenius norm of
- * @returns {Number} Frobenius norm
- */
-mat2.frob = function (a) {
- return (Math.sqrt(Math.pow(a.m00, 2) + Math.pow(a.m01, 2) + Math.pow(a.m02, 2) + Math.pow(a.m03, 2)));
-};
-
-/**
- * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
- * @param {mat2} L the lower triangular matrix
- * @param {mat2} D the diagonal matrix
- * @param {mat2} U the upper triangular matrix
- * @param {mat2} a the input matrix to factorize
- */
-
-mat2.LDU = function (L, D, U, a) {
- L.m02 = a.m02 / a.m00;
- U.m00 = a.m00;
- U.m01 = a.m01;
- U.m03 = a.m03 - L.m02 * U.m01;
-};
-
-/**
- * Adds two mat2's
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the first operand
- * @param {mat2} b the second operand
- * @returns {mat2} out
- */
-mat2.add = function (out, a, b) {
- out.m00 = a.m00 + b.m00;
- out.m01 = a.m01 + b.m01;
- out.m02 = a.m02 + b.m02;
- out.m03 = a.m03 + b.m03;
- return out;
-};
-
-/**
- * Subtracts matrix b from matrix a
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the first operand
- * @param {mat2} b the second operand
- * @returns {mat2} out
- */
-mat2.subtract = function (out, a, b) {
- out.m00 = a.m00 - b.m00;
- out.m01 = a.m01 - b.m01;
- out.m02 = a.m02 - b.m02;
- out.m03 = a.m03 - b.m03;
- return out;
-};
-
-/**
- * Alias for {@link mat2.subtract}
- * @function
- */
-mat2.sub = mat2.subtract;
-
-/**
- * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
- *
- * @param {mat2} a The first matrix.
- * @param {mat2} b The second matrix.
- * @returns {Boolean} True if the matrices are equal, false otherwise.
- */
-mat2.exactEquals = function (a, b) {
- return a.m00 === b.m00 && a.m01 === b.m01 && a.m02 === b.m02 && a.m03 === b.m03;
-};
-
-/**
- * Returns whether or not the matrices have approximately the same elements in the same position.
- *
- * @param {mat2} a The first matrix.
- * @param {mat2} b The second matrix.
- * @returns {Boolean} True if the matrices are equal, false otherwise.
- */
-mat2.equals = function (a, b) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03;
- var b0 = b.m00, b1 = b.m01, b2 = b.m02, b3 = b.m03;
- return (
- Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
- Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
- Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3))
- );
-};
-
-/**
- * Multiply each element of the matrix by a scalar.
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the matrix to scale
- * @param {Number} b amount to scale the matrix's elements by
- * @returns {mat2} out
- */
-mat2.multiplyScalar = function (out, a, b) {
- out.m00 = a.m00 * b;
- out.m01 = a.m01 * b;
- out.m02 = a.m02 * b;
- out.m03 = a.m03 * b;
- return out;
-};
-
-/**
- * Adds two mat2's after multiplying each element of the second operand by a scalar value.
- *
- * @param {mat2} out the receiving vector
- * @param {mat2} a the first operand
- * @param {mat2} b the second operand
- * @param {Number} scale the amount to scale b's elements by before adding
- * @returns {mat2} out
- */
-mat2.multiplyScalarAndAdd = function (out, a, b, scale) {
- out.m00 = a.m00 + (b.m00 * scale);
- out.m01 = a.m01 + (b.m01 * scale);
- out.m02 = a.m02 + (b.m02 * scale);
- out.m03 = a.m03 + (b.m03 * scale);
- return out;
-};
-
-var _tmp$6 = new Array(6);
-
-var _mat23 = function _mat23(m00, m01, m02, m03, m04, m05) {
- this.m00 = m00;
- this.m01 = m01;
- this.m02 = m02;
- this.m03 = m03;
- this.m04 = m04;
- this.m05 = m05;
-};
-
-_mat23.prototype.toJSON = function toJSON () {
- _tmp$6[0] = this.m00;
- _tmp$6[1] = this.m01;
- _tmp$6[2] = this.m02;
- _tmp$6[3] = this.m03;
- _tmp$6[4] = this.m04;
- _tmp$6[5] = this.m05;
-
- return _tmp$6;
-};
-
-/**
- * @class 2x3 Matrix
- * @name mat23
- *
- * @description
- * A mat23 contains six elements defined as:
- *
- * [a, c, tx,
- * b, d, ty]
- *
- * This is a short form for the 3x3 matrix:
- *
- * [a, c, tx,
- * b, d, ty,
- * 0, 0, 1]
- *
- * The last row is ignored so the array is shorter and operations are faster.
- */
-var mat23 = {};
-
-/**
- * Creates a new identity mat23
- *
- * @returns {mat23} a new 2x3 matrix
- */
-mat23.create = function () {
- return new _mat23(
- 1, 0,
- 0, 1,
- 0, 0
- );
-};
-
-/**
- * Create a new mat23 with the given values
- *
- * @param {Number} a Component A (index 0)
- * @param {Number} b Component B (index 1)
- * @param {Number} c Component C (index 2)
- * @param {Number} d Component D (index 3)
- * @param {Number} tx Component TX (index 4)
- * @param {Number} ty Component TY (index 5)
- * @returns {mat23} A new mat23
- */
-mat23.new = function (a, b, c, d, tx, ty) {
- return new _mat23(
- a, b,
- c, d,
- tx, ty
- );
-};
-
-/**
- * Creates a new mat23 initialized with values from an existing matrix
- *
- * @param {mat23} a matrix to clone
- * @returns {mat23} a new 2x3 matrix
- */
-mat23.clone = function (a) {
- return new _mat23(
- a.m00, a.m01,
- a.m02, a.m03,
- a.m04, a.m05
- );
-};
-
-/**
- * Copy the values from one mat23 to another
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the source matrix
- * @returns {mat23} out
- */
-mat23.copy = function (out, a) {
- out.m00 = a.m00;
- out.m01 = a.m01;
- out.m02 = a.m02;
- out.m03 = a.m03;
- out.m04 = a.m04;
- out.m05 = a.m05;
- return out;
-};
-
-/**
- * Set a mat23 to the identity matrix
- *
- * @param {mat23} out the receiving matrix
- * @returns {mat23} out
- */
-mat23.identity = function (out) {
- out.m00 = 1;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 1;
- out.m04 = 0;
- out.m05 = 0;
- return out;
-};
-
-/**
- * Set the components of a mat23 to the given values
- *
- * @param {mat23} out the receiving matrix
- * @param {Number} a Component A (index 0)
- * @param {Number} b Component B (index 1)
- * @param {Number} c Component C (index 2)
- * @param {Number} d Component D (index 3)
- * @param {Number} tx Component TX (index 4)
- * @param {Number} ty Component TY (index 5)
- * @returns {mat23} out
- */
-mat23.set = function (out, a, b, c, d, tx, ty) {
- out.m00 = a;
- out.m01 = b;
- out.m02 = c;
- out.m03 = d;
- out.m04 = tx;
- out.m05 = ty;
- return out;
-};
-
-/**
- * Inverts a mat23
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the source matrix
- * @returns {mat23} out
- */
-mat23.invert = function (out, a) {
- var aa = a.m00, ab = a.m01, ac = a.m02, ad = a.m03,
- atx = a.m04, aty = a.m05;
-
- var det = aa * ad - ab * ac;
- if (!det) {
- return null;
- }
- det = 1.0 / det;
-
- out.m00 = ad * det;
- out.m01 = -ab * det;
- out.m02 = -ac * det;
- out.m03 = aa * det;
- out.m04 = (ac * aty - ad * atx) * det;
- out.m05 = (ab * atx - aa * aty) * det;
- return out;
-};
-
-/**
- * Calculates the determinant of a mat23
- *
- * @param {mat23} a the source matrix
- * @returns {Number} determinant of a
- */
-mat23.determinant = function (a) {
- return a.m00 * a.m03 - a.m01 * a.m02;
-};
-
-/**
- * Multiplies two mat23's
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the first operand
- * @param {mat23} b the second operand
- * @returns {mat23} out
- */
-mat23.multiply = function (out, a, b) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03, a4 = a.m04, a5 = a.m05,
- b0 = b.m00, b1 = b.m01, b2 = b.m02, b3 = b.m03, b4 = b.m04, b5 = b.m05;
- out.m00 = a0 * b0 + a2 * b1;
- out.m01 = a1 * b0 + a3 * b1;
- out.m02 = a0 * b2 + a2 * b3;
- out.m03 = a1 * b2 + a3 * b3;
- out.m04 = a0 * b4 + a2 * b5 + a4;
- out.m05 = a1 * b4 + a3 * b5 + a5;
- return out;
-};
-
-/**
- * Alias for {@link mat23.multiply}
- * @function
- */
-mat23.mul = mat23.multiply;
-
-/**
- * Rotates a mat23 by the given angle
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat23} out
- */
-mat23.rotate = function (out, a, rad) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03, a4 = a.m04, a5 = a.m05,
- s = Math.sin(rad),
- c = Math.cos(rad);
- out.m00 = a0 * c + a2 * s;
- out.m01 = a1 * c + a3 * s;
- out.m02 = a0 * -s + a2 * c;
- out.m03 = a1 * -s + a3 * c;
- out.m04 = a4;
- out.m05 = a5;
- return out;
-};
-
-/**
- * Scales the mat23 by the dimensions in the given vec2
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the matrix to translate
- * @param {vec2} v the vec2 to scale the matrix by
- * @returns {mat23} out
- **/
-mat23.scale = function (out, a, v) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03, a4 = a.m04, a5 = a.m05,
- v0 = v.x, v1 = v.y;
- out.m00 = a0 * v0;
- out.m01 = a1 * v0;
- out.m02 = a2 * v1;
- out.m03 = a3 * v1;
- out.m04 = a4;
- out.m05 = a5;
- return out;
-};
-
-/**
- * Translates the mat23 by the dimensions in the given vec2
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the matrix to translate
- * @param {vec2} v the vec2 to translate the matrix by
- * @returns {mat23} out
- **/
-mat23.translate = function (out, a, v) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03, a4 = a.m04, a5 = a.m05,
- v0 = v.x, v1 = v.y;
- out.m00 = a0;
- out.m01 = a1;
- out.m02 = a2;
- out.m03 = a3;
- out.m04 = a0 * v0 + a2 * v1 + a4;
- out.m05 = a1 * v0 + a3 * v1 + a5;
- return out;
-};
-
-/**
- * Creates a matrix from a given angle
- * This is equivalent to (but much faster than):
- *
- * mat23.identity(dest);
- * mat23.rotate(dest, dest, rad);
- *
- * @param {mat23} out mat23 receiving operation result
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat23} out
- */
-mat23.fromRotation = function (out, rad) {
- var s = Math.sin(rad), c = Math.cos(rad);
- out.m00 = c;
- out.m01 = s;
- out.m02 = -s;
- out.m03 = c;
- out.m04 = 0;
- out.m05 = 0;
- return out;
-};
-
-/**
- * Creates a matrix from a vector scaling
- * This is equivalent to (but much faster than):
- *
- * mat23.identity(dest);
- * mat23.scale(dest, dest, vec);
- *
- * @param {mat23} out mat23 receiving operation result
- * @param {vec2} v Scaling vector
- * @returns {mat23} out
- */
-mat23.fromScaling = function (out, v) {
- out.m00 = v.m00;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = v.m01;
- out.m04 = 0;
- out.m05 = 0;
- return out;
-};
-
-/**
- * Creates a matrix from a vector translation
- * This is equivalent to (but much faster than):
- *
- * mat23.identity(dest);
- * mat23.translate(dest, dest, vec);
- *
- * @param {mat23} out mat23 receiving operation result
- * @param {vec2} v Translation vector
- * @returns {mat23} out
- */
-mat23.fromTranslation = function (out, v) {
- out.m00 = 1;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 1;
- out.m04 = v.x;
- out.m05 = v.y;
- return out;
-};
-
-/**
- * Returns a string representation of a mat23
- *
- * @param {mat23} a matrix to represent as a string
- * @returns {String} string representation of the matrix
- */
-mat23.str = function (a) {
- return ("mat23(" + (a.m00) + ", " + (a.m01) + ", " + (a.m02) + ", " + (a.m03) + ", " + (a.m04) + ", " + (a.m05) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {mat23} m
- * @returns {array}
- */
-mat23.array = function (out, m) {
- out[0] = m.m00;
- out[1] = m.m01;
- out[2] = m.m02;
- out[3] = m.m03;
- out[4] = m.m04;
- out[5] = m.m05;
-
- return out;
-};
-
-/**
- * Returns typed array to 16 float array
- *
- * @param {array} out
- * @param {mat23} m
- * @returns {array}
- */
-mat23.array4x4 = function (out, m) {
- out[0] = m.m00;
- out[1] = m.m01;
- out[2] = 0;
- out[3] = 0;
- out[4] = m.m02;
- out[5] = m.m03;
- out[6] = 0;
- out[7] = 0;
- out[8] = 0;
- out[9] = 0;
- out[10] = 1;
- out[11] = 0;
- out[12] = m.m04;
- out[13] = m.m05;
- out[14] = 0;
- out[15] = 1;
-
- return out;
-};
-
-/**
- * Returns Frobenius norm of a mat23
- *
- * @param {mat23} a the matrix to calculate Frobenius norm of
- * @returns {Number} Frobenius norm
- */
-mat23.frob = function (a) {
- return (Math.sqrt(Math.pow(a.m00, 2) + Math.pow(a.m01, 2) + Math.pow(a.m02, 2) + Math.pow(a.m03, 2) + Math.pow(a.m04, 2) + Math.pow(a.m05, 2) + 1));
-};
-
-/**
- * Adds two mat23's
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the first operand
- * @param {mat23} b the second operand
- * @returns {mat23} out
- */
-mat23.add = function (out, a, b) {
- out.m00 = a.m00 + b.m00;
- out.m01 = a.m01 + b.m01;
- out.m02 = a.m02 + b.m02;
- out.m03 = a.m03 + b.m03;
- out.m04 = a.m04 + b.m04;
- out.m05 = a.m05 + b.m05;
- return out;
-};
-
-/**
- * Subtracts matrix b from matrix a
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the first operand
- * @param {mat23} b the second operand
- * @returns {mat23} out
- */
-mat23.subtract = function (out, a, b) {
- out.m00 = a.m00 - b.m00;
- out.m01 = a.m01 - b.m01;
- out.m02 = a.m02 - b.m02;
- out.m03 = a.m03 - b.m03;
- out.m04 = a.m04 - b.m04;
- out.m05 = a.m05 - b.m05;
- return out;
-};
-
-/**
- * Alias for {@link mat23.subtract}
- * @function
- */
-mat23.sub = mat23.subtract;
-
-/**
- * Multiply each element of the matrix by a scalar.
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the matrix to scale
- * @param {Number} b amount to scale the matrix's elements by
- * @returns {mat23} out
- */
-mat23.multiplyScalar = function (out, a, b) {
- out.m00 = a.m00 * b;
- out.m01 = a.m01 * b;
- out.m02 = a.m02 * b;
- out.m03 = a.m03 * b;
- out.m04 = a.m04 * b;
- out.m05 = a.m05 * b;
- return out;
-};
-
-/**
- * Adds two mat23's after multiplying each element of the second operand by a scalar value.
- *
- * @param {mat23} out the receiving vector
- * @param {mat23} a the first operand
- * @param {mat23} b the second operand
- * @param {Number} scale the amount to scale b's elements by before adding
- * @returns {mat23} out
- */
-mat23.multiplyScalarAndAdd = function (out, a, b, scale) {
- out.m00 = a.m00 + (b.m00 * scale);
- out.m01 = a.m01 + (b.m01 * scale);
- out.m02 = a.m02 + (b.m02 * scale);
- out.m03 = a.m03 + (b.m03 * scale);
- out.m04 = a.m04 + (b.m04 * scale);
- out.m05 = a.m05 + (b.m05 * scale);
- return out;
-};
-
-/**
- * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
- *
- * @param {mat23} a The first matrix.
- * @param {mat23} b The second matrix.
- * @returns {Boolean} True if the matrices are equal, false otherwise.
- */
-mat23.exactEquals = function (a, b) {
- return a.m00 === b.m00 && a.m01 === b.m01 && a.m02 === b.m02 && a.m03 === b.m03 && a.m04 === b.m04 && a.m05 === b.m05;
-};
-
-/**
- * Returns whether or not the matrices have approximately the same elements in the same position.
- *
- * @param {mat23} a The first matrix.
- * @param {mat23} b The second matrix.
- * @returns {Boolean} True if the matrices are equal, false otherwise.
- */
-mat23.equals = function (a, b) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03, a4 = a.m04, a5 = a.m05;
- var b0 = b.m00, b1 = b.m01, b2 = b.m02, b3 = b.m03, b4 = b.m04, b5 = b.m05;
- return (
- Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
- Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
- Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&
- Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&
- Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5))
- );
-};
-
-var _tmp$7 = new Array(16);
-
-var _mat4 = function _mat4(
- m00, m01, m02, m03,
- m04, m05, m06, m07,
- m08, m09, m10, m11,
- m12, m13, m14, m15
-) {
- this.m00 = m00;
- this.m01 = m01;
- this.m02 = m02;
- this.m03 = m03;
- this.m04 = m04;
- this.m05 = m05;
- this.m06 = m06;
- this.m07 = m07;
- this.m08 = m08;
- this.m09 = m09;
- this.m10 = m10;
- this.m11 = m11;
- this.m12 = m12;
- this.m13 = m13;
- this.m14 = m14;
- this.m15 = m15;
-};
-
-_mat4.prototype.toJSON = function toJSON () {
- _tmp$7[0] = this.m00;
- _tmp$7[1] = this.m01;
- _tmp$7[2] = this.m02;
- _tmp$7[3] = this.m03;
- _tmp$7[4] = this.m04;
- _tmp$7[5] = this.m05;
- _tmp$7[6] = this.m06;
- _tmp$7[7] = this.m07;
- _tmp$7[8] = this.m08;
- _tmp$7[9] = this.m09;
- _tmp$7[10] = this.m10;
- _tmp$7[11] = this.m11;
- _tmp$7[12] = this.m12;
- _tmp$7[13] = this.m13;
- _tmp$7[14] = this.m14;
- _tmp$7[15] = this.m15;
-
- return _tmp$7;
-};
-
-/**
- * @class 4x4 Matrix
- * @name mat4
- *
- * NOTE: we use column-major matrix for all matrix calculation.
- *
- * This may lead to some confusion when referencing OpenGL documentation,
- * however, which represents out all matricies in column-major format.
- * This means that while in code a matrix may be typed out as:
- *
- * [1, 0, 0, 0,
- * 0, 1, 0, 0,
- * 0, 0, 1, 0,
- * x, y, z, 0]
- *
- * The same matrix in the [OpenGL documentation](https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTranslate.xml)
- * is written as:
- *
- * 1 0 0 x
- * 0 1 0 y
- * 0 0 1 z
- * 0 0 0 0
- *
- * Please rest assured, however, that they are the same thing!
- * This is not unique to glMatrix, either, as OpenGL developers have long been confused by the
- * apparent lack of consistency between the memory layout and the documentation.
- */
-var mat4 = {};
-
-/**
- * Creates a new identity mat4
- *
- * @returns {mat4} a new 4x4 matrix
- */
-mat4.create = function () {
- return new _mat4(
- 1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1
- );
-};
-
-/**
- * Create a new mat4 with the given values
- *
- * @param {Number} m00 Component in column 0, row 0 position (index 0)
- * @param {Number} m01 Component in column 0, row 1 position (index 1)
- * @param {Number} m02 Component in column 0, row 2 position (index 2)
- * @param {Number} m03 Component in column 0, row 3 position (index 3)
- * @param {Number} m10 Component in column 1, row 0 position (index 4)
- * @param {Number} m11 Component in column 1, row 1 position (index 5)
- * @param {Number} m12 Component in column 1, row 2 position (index 6)
- * @param {Number} m13 Component in column 1, row 3 position (index 7)
- * @param {Number} m20 Component in column 2, row 0 position (index 8)
- * @param {Number} m21 Component in column 2, row 1 position (index 9)
- * @param {Number} m22 Component in column 2, row 2 position (index 10)
- * @param {Number} m23 Component in column 2, row 3 position (index 11)
- * @param {Number} m30 Component in column 3, row 0 position (index 12)
- * @param {Number} m31 Component in column 3, row 1 position (index 13)
- * @param {Number} m32 Component in column 3, row 2 position (index 14)
- * @param {Number} m33 Component in column 3, row 3 position (index 15)
- * @returns {mat4} A new mat4
- */
-mat4.new = function (m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
- return new _mat4(
- m00, m01, m02, m03,
- m10, m11, m12, m13,
- m20, m21, m22, m23,
- m30, m31, m32, m33
- );
-};
-
-/**
- * Creates a new mat4 initialized with values from an existing matrix
- *
- * @param {mat4} a matrix to clone
- * @returns {mat4} a new 4x4 matrix
- */
-mat4.clone = function (a) {
- return new _mat4(
- a.m00, a.m01, a.m02, a.m03,
- a.m04, a.m05, a.m06, a.m07,
- a.m08, a.m09, a.m10, a.m11,
- a.m12, a.m13, a.m14, a.m15
- );
-};
-
-/**
- * Copy the values from one mat4 to another
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the source matrix
- * @returns {mat4} out
- */
-mat4.copy = function (out, a) {
- out.m00 = a.m00;
- out.m01 = a.m01;
- out.m02 = a.m02;
- out.m03 = a.m03;
- out.m04 = a.m04;
- out.m05 = a.m05;
- out.m06 = a.m06;
- out.m07 = a.m07;
- out.m08 = a.m08;
- out.m09 = a.m09;
- out.m10 = a.m10;
- out.m11 = a.m11;
- out.m12 = a.m12;
- out.m13 = a.m13;
- out.m14 = a.m14;
- out.m15 = a.m15;
- return out;
-};
-
-/**
- * Set the components of a mat4 to the given values
- *
- * @param {mat4} out the receiving matrix
- * @param {Number} m00 Component in column 0, row 0 position (index 0)
- * @param {Number} m01 Component in column 0, row 1 position (index 1)
- * @param {Number} m02 Component in column 0, row 2 position (index 2)
- * @param {Number} m03 Component in column 0, row 3 position (index 3)
- * @param {Number} m10 Component in column 1, row 0 position (index 4)
- * @param {Number} m11 Component in column 1, row 1 position (index 5)
- * @param {Number} m12 Component in column 1, row 2 position (index 6)
- * @param {Number} m13 Component in column 1, row 3 position (index 7)
- * @param {Number} m20 Component in column 2, row 0 position (index 8)
- * @param {Number} m21 Component in column 2, row 1 position (index 9)
- * @param {Number} m22 Component in column 2, row 2 position (index 10)
- * @param {Number} m23 Component in column 2, row 3 position (index 11)
- * @param {Number} m30 Component in column 3, row 0 position (index 12)
- * @param {Number} m31 Component in column 3, row 1 position (index 13)
- * @param {Number} m32 Component in column 3, row 2 position (index 14)
- * @param {Number} m33 Component in column 3, row 3 position (index 15)
- * @returns {mat4} out
- */
-mat4.set = function (out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
- out.m00 = m00;
- out.m01 = m01;
- out.m02 = m02;
- out.m03 = m03;
- out.m04 = m10;
- out.m05 = m11;
- out.m06 = m12;
- out.m07 = m13;
- out.m08 = m20;
- out.m09 = m21;
- out.m10 = m22;
- out.m11 = m23;
- out.m12 = m30;
- out.m13 = m31;
- out.m14 = m32;
- out.m15 = m33;
- return out;
-};
-
-
-/**
- * Set a mat4 to the identity matrix
- *
- * @param {mat4} out the receiving matrix
- * @returns {mat4} out
- */
-mat4.identity = function (out) {
- out.m00 = 1;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 0;
- out.m05 = 1;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 0;
- out.m09 = 0;
- out.m10 = 1;
- out.m11 = 0;
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = 0;
- out.m15 = 1;
- return out;
-};
-
-/**
- * Transpose the values of a mat4
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the source matrix
- * @returns {mat4} out
- */
-mat4.transpose = function (out, a) {
- // If we are transposing ourselves we can skip a few steps but have to cache some values
- if (out === a) {
- var a01 = a.m01, a02 = a.m02, a03 = a.m03,
- a12 = a.m06, a13 = a.m07,
- a23 = a.m11;
-
- out.m01 = a.m04;
- out.m02 = a.m08;
- out.m03 = a.m12;
- out.m04 = a01;
- out.m06 = a.m09;
- out.m07 = a.m13;
- out.m08 = a02;
- out.m09 = a12;
- out.m11 = a.m14;
- out.m12 = a03;
- out.m13 = a13;
- out.m14 = a23;
- } else {
- out.m00 = a.m00;
- out.m01 = a.m04;
- out.m02 = a.m08;
- out.m03 = a.m12;
- out.m04 = a.m01;
- out.m05 = a.m05;
- out.m06 = a.m09;
- out.m07 = a.m13;
- out.m08 = a.m02;
- out.m09 = a.m06;
- out.m10 = a.m10;
- out.m11 = a.m14;
- out.m12 = a.m03;
- out.m13 = a.m07;
- out.m14 = a.m11;
- out.m15 = a.m15;
- }
-
- return out;
-};
-
-/**
- * Inverts a mat4
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the source matrix
- * @returns {mat4} out
- */
-mat4.invert = function (out, a) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02, a03 = a.m03,
- a10 = a.m04, a11 = a.m05, a12 = a.m06, a13 = a.m07,
- a20 = a.m08, a21 = a.m09, a22 = a.m10, a23 = a.m11,
- a30 = a.m12, a31 = a.m13, a32 = a.m14, a33 = a.m15;
-
- var b00 = a00 * a11 - a01 * a10;
- var b01 = a00 * a12 - a02 * a10;
- var b02 = a00 * a13 - a03 * a10;
- var b03 = a01 * a12 - a02 * a11;
- var b04 = a01 * a13 - a03 * a11;
- var b05 = a02 * a13 - a03 * a12;
- var b06 = a20 * a31 - a21 * a30;
- var b07 = a20 * a32 - a22 * a30;
- var b08 = a20 * a33 - a23 * a30;
- var b09 = a21 * a32 - a22 * a31;
- var b10 = a21 * a33 - a23 * a31;
- var b11 = a22 * a33 - a23 * a32;
-
- // Calculate the determinant
- var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
-
- if (!det) {
- return null;
- }
- det = 1.0 / det;
-
- out.m00 = (a11 * b11 - a12 * b10 + a13 * b09) * det;
- out.m01 = (a02 * b10 - a01 * b11 - a03 * b09) * det;
- out.m02 = (a31 * b05 - a32 * b04 + a33 * b03) * det;
- out.m03 = (a22 * b04 - a21 * b05 - a23 * b03) * det;
- out.m04 = (a12 * b08 - a10 * b11 - a13 * b07) * det;
- out.m05 = (a00 * b11 - a02 * b08 + a03 * b07) * det;
- out.m06 = (a32 * b02 - a30 * b05 - a33 * b01) * det;
- out.m07 = (a20 * b05 - a22 * b02 + a23 * b01) * det;
- out.m08 = (a10 * b10 - a11 * b08 + a13 * b06) * det;
- out.m09 = (a01 * b08 - a00 * b10 - a03 * b06) * det;
- out.m10 = (a30 * b04 - a31 * b02 + a33 * b00) * det;
- out.m11 = (a21 * b02 - a20 * b04 - a23 * b00) * det;
- out.m12 = (a11 * b07 - a10 * b09 - a12 * b06) * det;
- out.m13 = (a00 * b09 - a01 * b07 + a02 * b06) * det;
- out.m14 = (a31 * b01 - a30 * b03 - a32 * b00) * det;
- out.m15 = (a20 * b03 - a21 * b01 + a22 * b00) * det;
-
- return out;
-};
-
-/**
- * Calculates the adjugate of a mat4
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the source matrix
- * @returns {mat4} out
- */
-mat4.adjoint = function (out, a) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02, a03 = a.m03,
- a10 = a.m04, a11 = a.m05, a12 = a.m06, a13 = a.m07,
- a20 = a.m08, a21 = a.m09, a22 = a.m10, a23 = a.m11,
- a30 = a.m12, a31 = a.m13, a32 = a.m14, a33 = a.m15;
-
- out.m00 = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22));
- out.m01 = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
- out.m02 = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12));
- out.m03 = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
- out.m04 = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
- out.m05 = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22));
- out.m06 = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
- out.m07 = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12));
- out.m08 = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21));
- out.m09 = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
- out.m10 = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11));
- out.m11 = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
- out.m12 = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
- out.m13 = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21));
- out.m14 = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
- out.m15 = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11));
- return out;
-};
-
-/**
- * Calculates the determinant of a mat4
- *
- * @param {mat4} a the source matrix
- * @returns {Number} determinant of a
- */
-mat4.determinant = function (a) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02, a03 = a.m03,
- a10 = a.m04, a11 = a.m05, a12 = a.m06, a13 = a.m07,
- a20 = a.m08, a21 = a.m09, a22 = a.m10, a23 = a.m11,
- a30 = a.m12, a31 = a.m13, a32 = a.m14, a33 = a.m15;
-
- var b00 = a00 * a11 - a01 * a10;
- var b01 = a00 * a12 - a02 * a10;
- var b02 = a00 * a13 - a03 * a10;
- var b03 = a01 * a12 - a02 * a11;
- var b04 = a01 * a13 - a03 * a11;
- var b05 = a02 * a13 - a03 * a12;
- var b06 = a20 * a31 - a21 * a30;
- var b07 = a20 * a32 - a22 * a30;
- var b08 = a20 * a33 - a23 * a30;
- var b09 = a21 * a32 - a22 * a31;
- var b10 = a21 * a33 - a23 * a31;
- var b11 = a22 * a33 - a23 * a32;
-
- // Calculate the determinant
- return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
-};
-
-/**
- * Multiplies two mat4's explicitly
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the first operand
- * @param {mat4} b the second operand
- * @returns {mat4} out
- */
-mat4.multiply = function (out, a, b) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02, a03 = a.m03,
- a10 = a.m04, a11 = a.m05, a12 = a.m06, a13 = a.m07,
- a20 = a.m08, a21 = a.m09, a22 = a.m10, a23 = a.m11,
- a30 = a.m12, a31 = a.m13, a32 = a.m14, a33 = a.m15;
-
- // Cache only the current line of the second matrix
- var b0 = b.m00, b1 = b.m01, b2 = b.m02, b3 = b.m03;
- out.m00 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
- out.m01 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
- out.m02 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
- out.m03 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
-
- b0 = b.m04; b1 = b.m05; b2 = b.m06; b3 = b.m07;
- out.m04 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
- out.m05 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
- out.m06 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
- out.m07 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
-
- b0 = b.m08; b1 = b.m09; b2 = b.m10; b3 = b.m11;
- out.m08 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
- out.m09 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
- out.m10 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
- out.m11 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
-
- b0 = b.m12; b1 = b.m13; b2 = b.m14; b3 = b.m15;
- out.m12 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
- out.m13 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
- out.m14 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
- out.m15 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
- return out;
-};
-
-/**
- * Alias for {@link mat4.multiply}
- * @function
- */
-mat4.mul = mat4.multiply;
-
-/**
- * Translate a mat4 by the given vector
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the matrix to translate
- * @param {vec3} v vector to translate by
- * @returns {mat4} out
- */
-mat4.translate = function (out, a, v) {
- var x = v.x, y = v.y, z = v.z,
- a00, a01, a02, a03,
- a10, a11, a12, a13,
- a20, a21, a22, a23;
-
- if (a === out) {
- out.m12 = a.m00 * x + a.m04 * y + a.m08 * z + a.m12;
- out.m13 = a.m01 * x + a.m05 * y + a.m09 * z + a.m13;
- out.m14 = a.m02 * x + a.m06 * y + a.m10 * z + a.m14;
- out.m15 = a.m03 * x + a.m07 * y + a.m11 * z + a.m15;
- } else {
- a00 = a.m00; a01 = a.m01; a02 = a.m02; a03 = a.m03;
- a10 = a.m04; a11 = a.m05; a12 = a.m06; a13 = a.m07;
- a20 = a.m08; a21 = a.m09; a22 = a.m10; a23 = a.m11;
-
- out.m00 = a00; out.m01 = a01; out.m02 = a02; out.m03 = a03;
- out.m04 = a10; out.m05 = a11; out.m06 = a12; out.m07 = a13;
- out.m08 = a20; out.m09 = a21; out.m10 = a22; out.m11 = a23;
-
- out.m12 = a00 * x + a10 * y + a20 * z + a.m12;
- out.m13 = a01 * x + a11 * y + a21 * z + a.m13;
- out.m14 = a02 * x + a12 * y + a22 * z + a.m14;
- out.m15 = a03 * x + a13 * y + a23 * z + a.m15;
- }
-
- return out;
-};
-
-/**
- * Scales the mat4 by the dimensions in the given vec3
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the matrix to scale
- * @param {vec3} v the vec3 to scale the matrix by
- * @returns {mat4} out
- **/
-mat4.scale = function (out, a, v) {
- var x = v.x, y = v.y, z = v.z;
-
- out.m00 = a.m00 * x;
- out.m01 = a.m01 * x;
- out.m02 = a.m02 * x;
- out.m03 = a.m03 * x;
- out.m04 = a.m04 * y;
- out.m05 = a.m05 * y;
- out.m06 = a.m06 * y;
- out.m07 = a.m07 * y;
- out.m08 = a.m08 * z;
- out.m09 = a.m09 * z;
- out.m10 = a.m10 * z;
- out.m11 = a.m11 * z;
- out.m12 = a.m12;
- out.m13 = a.m13;
- out.m14 = a.m14;
- out.m15 = a.m15;
- return out;
-};
-
-/**
- * Rotates a mat4 by the given angle around the given axis
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @param {vec3} axis the axis to rotate around
- * @returns {mat4} out
- */
-mat4.rotate = function (out, a, rad, axis) {
- var x = axis.x, y = axis.y, z = axis.z;
- var s, c, t,
- a00, a01, a02, a03,
- a10, a11, a12, a13,
- a20, a21, a22, a23,
- b00, b01, b02,
- b10, b11, b12,
- b20, b21, b22;
-
- var len = Math.sqrt(x * x + y * y + z * z);
-
- if (Math.abs(len) < EPSILON) {
- return null;
- }
-
- len = 1 / len;
- x *= len;
- y *= len;
- z *= len;
-
- s = Math.sin(rad);
- c = Math.cos(rad);
- t = 1 - c;
-
- a00 = a.m00; a01 = a.m01; a02 = a.m02; a03 = a.m03;
- a10 = a.m04; a11 = a.m05; a12 = a.m06; a13 = a.m07;
- a20 = a.m08; a21 = a.m09; a22 = a.m10; a23 = a.m11;
-
- // Construct the elements of the rotation matrix
- b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;
- b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;
- b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;
-
- // Perform rotation-specific matrix multiplication
- out.m00 = a00 * b00 + a10 * b01 + a20 * b02;
- out.m01 = a01 * b00 + a11 * b01 + a21 * b02;
- out.m02 = a02 * b00 + a12 * b01 + a22 * b02;
- out.m03 = a03 * b00 + a13 * b01 + a23 * b02;
- out.m04 = a00 * b10 + a10 * b11 + a20 * b12;
- out.m05 = a01 * b10 + a11 * b11 + a21 * b12;
- out.m06 = a02 * b10 + a12 * b11 + a22 * b12;
- out.m07 = a03 * b10 + a13 * b11 + a23 * b12;
- out.m08 = a00 * b20 + a10 * b21 + a20 * b22;
- out.m09 = a01 * b20 + a11 * b21 + a21 * b22;
- out.m10 = a02 * b20 + a12 * b21 + a22 * b22;
- out.m11 = a03 * b20 + a13 * b21 + a23 * b22;
-
- // If the source and destination differ, copy the unchanged last row
- if (a !== out) {
- out.m12 = a.m12;
- out.m13 = a.m13;
- out.m14 = a.m14;
- out.m15 = a.m15;
- }
-
- return out;
-};
-
-/**
- * Rotates a matrix by the given angle around the X axis
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat4} out
- */
-mat4.rotateX = function (out, a, rad) {
- var s = Math.sin(rad),
- c = Math.cos(rad),
- a10 = a.m04,
- a11 = a.m05,
- a12 = a.m06,
- a13 = a.m07,
- a20 = a.m08,
- a21 = a.m09,
- a22 = a.m10,
- a23 = a.m11;
-
- if (a !== out) { // If the source and destination differ, copy the unchanged rows
- out.m00 = a.m00;
- out.m01 = a.m01;
- out.m02 = a.m02;
- out.m03 = a.m03;
- out.m12 = a.m12;
- out.m13 = a.m13;
- out.m14 = a.m14;
- out.m15 = a.m15;
- }
-
- // Perform axis-specific matrix multiplication
- out.m04 = a10 * c + a20 * s;
- out.m05 = a11 * c + a21 * s;
- out.m06 = a12 * c + a22 * s;
- out.m07 = a13 * c + a23 * s;
- out.m08 = a20 * c - a10 * s;
- out.m09 = a21 * c - a11 * s;
- out.m10 = a22 * c - a12 * s;
- out.m11 = a23 * c - a13 * s;
-
- return out;
-};
-
-/**
- * Rotates a matrix by the given angle around the Y axis
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat4} out
- */
-mat4.rotateY = function (out, a, rad) {
- var s = Math.sin(rad),
- c = Math.cos(rad),
- a00 = a.m00,
- a01 = a.m01,
- a02 = a.m02,
- a03 = a.m03,
- a20 = a.m08,
- a21 = a.m09,
- a22 = a.m10,
- a23 = a.m11;
-
- if (a !== out) { // If the source and destination differ, copy the unchanged rows
- out.m04 = a.m04;
- out.m05 = a.m05;
- out.m06 = a.m06;
- out.m07 = a.m07;
- out.m12 = a.m12;
- out.m13 = a.m13;
- out.m14 = a.m14;
- out.m15 = a.m15;
- }
-
- // Perform axis-specific matrix multiplication
- out.m00 = a00 * c - a20 * s;
- out.m01 = a01 * c - a21 * s;
- out.m02 = a02 * c - a22 * s;
- out.m03 = a03 * c - a23 * s;
- out.m08 = a00 * s + a20 * c;
- out.m09 = a01 * s + a21 * c;
- out.m10 = a02 * s + a22 * c;
- out.m11 = a03 * s + a23 * c;
-
- return out;
-};
-
-/**
- * Rotates a matrix by the given angle around the Z axis
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat4} out
- */
-mat4.rotateZ = function (out, a, rad) {
- var s = Math.sin(rad),
- c = Math.cos(rad),
- a00 = a.m00,
- a01 = a.m01,
- a02 = a.m02,
- a03 = a.m03,
- a10 = a.m04,
- a11 = a.m05,
- a12 = a.m06,
- a13 = a.m07;
-
- // If the source and destination differ, copy the unchanged last row
- if (a !== out) {
- out.m08 = a.m08;
- out.m09 = a.m09;
- out.m10 = a.m10;
- out.m11 = a.m11;
- out.m12 = a.m12;
- out.m13 = a.m13;
- out.m14 = a.m14;
- out.m15 = a.m15;
- }
-
- // Perform axis-specific matrix multiplication
- out.m00 = a00 * c + a10 * s;
- out.m01 = a01 * c + a11 * s;
- out.m02 = a02 * c + a12 * s;
- out.m03 = a03 * c + a13 * s;
- out.m04 = a10 * c - a00 * s;
- out.m05 = a11 * c - a01 * s;
- out.m06 = a12 * c - a02 * s;
- out.m07 = a13 * c - a03 * s;
-
- return out;
-};
-
-/**
- * Creates a matrix from a vector translation
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.translate(dest, dest, vec);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {vec3} v Translation vector
- * @returns {mat4} out
- */
-mat4.fromTranslation = function (out, v) {
- out.m00 = 1;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 0;
- out.m05 = 1;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 0;
- out.m09 = 0;
- out.m10 = 1;
- out.m11 = 0;
- out.m12 = v.x;
- out.m13 = v.y;
- out.m14 = v.z;
- out.m15 = 1;
- return out;
-};
-
-/**
- * Creates a matrix from a vector scaling
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.scale(dest, dest, vec);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {vec3} v Scaling vector
- * @returns {mat4} out
- */
-mat4.fromScaling = function (out, v) {
- out.m00 = v.x;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 0;
- out.m05 = v.y;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 0;
- out.m09 = 0;
- out.m10 = v.z;
- out.m11 = 0;
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = 0;
- out.m15 = 1;
- return out;
-};
-
-/**
- * Creates a matrix from a given angle around a given axis
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.rotate(dest, dest, rad, axis);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {Number} rad the angle to rotate the matrix by
- * @param {vec3} axis the axis to rotate around
- * @returns {mat4} out
- */
-mat4.fromRotation = function (out, rad, axis) {
- var x = axis.x, y = axis.y, z = axis.z;
- var len = Math.sqrt(x * x + y * y + z * z);
- var s, c, t;
-
- if (Math.abs(len) < EPSILON) {
- return null;
- }
-
- len = 1 / len;
- x *= len;
- y *= len;
- z *= len;
-
- s = Math.sin(rad);
- c = Math.cos(rad);
- t = 1 - c;
-
- // Perform rotation-specific matrix multiplication
- out.m00 = x * x * t + c;
- out.m01 = y * x * t + z * s;
- out.m02 = z * x * t - y * s;
- out.m03 = 0;
- out.m04 = x * y * t - z * s;
- out.m05 = y * y * t + c;
- out.m06 = z * y * t + x * s;
- out.m07 = 0;
- out.m08 = x * z * t + y * s;
- out.m09 = y * z * t - x * s;
- out.m10 = z * z * t + c;
- out.m11 = 0;
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = 0;
- out.m15 = 1;
- return out;
-};
-
-/**
- * Creates a matrix from the given angle around the X axis
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.rotateX(dest, dest, rad);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat4} out
- */
-mat4.fromXRotation = function (out, rad) {
- var s = Math.sin(rad),
- c = Math.cos(rad);
-
- // Perform axis-specific matrix multiplication
- out.m00 = 1;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 0;
- out.m05 = c;
- out.m06 = s;
- out.m07 = 0;
- out.m08 = 0;
- out.m09 = -s;
- out.m10 = c;
- out.m11 = 0;
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = 0;
- out.m15 = 1;
- return out;
-};
-
-/**
- * Creates a matrix from the given angle around the Y axis
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.rotateY(dest, dest, rad);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat4} out
- */
-mat4.fromYRotation = function (out, rad) {
- var s = Math.sin(rad),
- c = Math.cos(rad);
-
- // Perform axis-specific matrix multiplication
- out.m00 = c;
- out.m01 = 0;
- out.m02 = -s;
- out.m03 = 0;
- out.m04 = 0;
- out.m05 = 1;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = s;
- out.m09 = 0;
- out.m10 = c;
- out.m11 = 0;
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = 0;
- out.m15 = 1;
- return out;
-};
-
-/**
- * Creates a matrix from the given angle around the Z axis
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.rotateZ(dest, dest, rad);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat4} out
- */
-mat4.fromZRotation = function (out, rad) {
- var s = Math.sin(rad),
- c = Math.cos(rad);
-
- // Perform axis-specific matrix multiplication
- out.m00 = c;
- out.m01 = s;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = -s;
- out.m05 = c;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 0;
- out.m09 = 0;
- out.m10 = 1;
- out.m11 = 0;
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = 0;
- out.m15 = 1;
- return out;
-};
-
-/**
- * Creates a matrix from a quaternion rotation and vector translation
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.translate(dest, vec);
- * let quatMat = mat4.create();
- * quat.toMat4(quat, quatMat);
- * mat4.multiply(dest, quatMat);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {quat} q Rotation quaternion
- * @param {vec3} v Translation vector
- * @returns {mat4} out
- */
-mat4.fromRT = function (out, q, v) {
- // Quaternion math
- var x = q.x, y = q.y, z = q.z, w = q.w;
- var x2 = x + x;
- var y2 = y + y;
- var z2 = z + z;
-
- var xx = x * x2;
- var xy = x * y2;
- var xz = x * z2;
- var yy = y * y2;
- var yz = y * z2;
- var zz = z * z2;
- var wx = w * x2;
- var wy = w * y2;
- var wz = w * z2;
-
- out.m00 = 1 - (yy + zz);
- out.m01 = xy + wz;
- out.m02 = xz - wy;
- out.m03 = 0;
- out.m04 = xy - wz;
- out.m05 = 1 - (xx + zz);
- out.m06 = yz + wx;
- out.m07 = 0;
- out.m08 = xz + wy;
- out.m09 = yz - wx;
- out.m10 = 1 - (xx + yy);
- out.m11 = 0;
- out.m12 = v.x;
- out.m13 = v.y;
- out.m14 = v.z;
- out.m15 = 1;
-
- return out;
-};
-
-/**
- * Returns the translation vector component of a transformation
- * matrix. If a matrix is built with fromRT,
- * the returned vector will be the same as the translation vector
- * originally supplied.
- * @param {vec3} out Vector to receive translation component
- * @param {mat4} mat Matrix to be decomposed (input)
- * @return {vec3} out
- */
-mat4.getTranslation = function (out, mat) {
- out.x = mat.m12;
- out.y = mat.m13;
- out.z = mat.m14;
-
- return out;
-};
-
-/**
- * Returns the scaling factor component of a transformation
- * matrix. If a matrix is built with fromRTS
- * with a normalized Quaternion paramter, the returned vector will be
- * the same as the scaling vector
- * originally supplied.
- * @param {vec3} out Vector to receive scaling factor component
- * @param {mat4} mat Matrix to be decomposed (input)
- * @return {vec3} out
- */
-mat4.getScaling = function (out, mat) {
- var m11 = mat.m00,
- m12 = mat.m01,
- m13 = mat.m02,
- m21 = mat.m04,
- m22 = mat.m05,
- m23 = mat.m06,
- m31 = mat.m08,
- m32 = mat.m09,
- m33 = mat.m10;
-
- out.x = Math.sqrt(m11 * m11 + m12 * m12 + m13 * m13);
- out.y = Math.sqrt(m21 * m21 + m22 * m22 + m23 * m23);
- out.z = Math.sqrt(m31 * m31 + m32 * m32 + m33 * m33);
-
- return out;
-};
-
-/**
- * Returns a quaternion representing the rotational component
- * of a transformation matrix. If a matrix is built with
- * fromRT, the returned quaternion will be the
- * same as the quaternion originally supplied.
- * @param {quat} out Quaternion to receive the rotation component
- * @param {mat4} mat Matrix to be decomposed (input)
- * @return {quat} out
- */
-mat4.getRotation = function (out, mat) {
- // Algorithm taken from http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
- var trace = mat.m00 + mat.m05 + mat.m10;
- var S = 0;
-
- if (trace > 0) {
- S = Math.sqrt(trace + 1.0) * 2;
- out.w = 0.25 * S;
- out.x = (mat.m06 - mat.m09) / S;
- out.y = (mat.m08 - mat.m02) / S;
- out.z = (mat.m01 - mat.m04) / S;
- } else if ((mat.m00 > mat.m05) & (mat.m00 > mat.m10)) {
- S = Math.sqrt(1.0 + mat.m00 - mat.m05 - mat.m10) * 2;
- out.w = (mat.m06 - mat.m09) / S;
- out.x = 0.25 * S;
- out.y = (mat.m01 + mat.m04) / S;
- out.z = (mat.m08 + mat.m02) / S;
- } else if (mat.m05 > mat.m10) {
- S = Math.sqrt(1.0 + mat.m05 - mat.m00 - mat.m10) * 2;
- out.w = (mat.m08 - mat.m02) / S;
- out.x = (mat.m01 + mat.m04) / S;
- out.y = 0.25 * S;
- out.z = (mat.m06 + mat.m09) / S;
- } else {
- S = Math.sqrt(1.0 + mat.m10 - mat.m00 - mat.m05) * 2;
- out.w = (mat.m01 - mat.m04) / S;
- out.x = (mat.m08 + mat.m02) / S;
- out.y = (mat.m06 + mat.m09) / S;
- out.z = 0.25 * S;
- }
-
- return out;
-};
-
-/**
- * Creates a matrix from a quaternion rotation, vector translation and vector scale
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.translate(dest, vec);
- * let quatMat = mat4.create();
- * quat.toMat4(quat, quatMat);
- * mat4.multiply(dest, quatMat);
- * mat4.scale(dest, scale)
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {quat} q Rotation quaternion
- * @param {vec3} v Translation vector
- * @param {vec3} s Scaling vector
- * @returns {mat4} out
- */
-mat4.fromRTS = function (out, q, v, s) {
- // Quaternion math
- var x = q.x, y = q.y, z = q.z, w = q.w;
- var x2 = x + x;
- var y2 = y + y;
- var z2 = z + z;
-
- var xx = x * x2;
- var xy = x * y2;
- var xz = x * z2;
- var yy = y * y2;
- var yz = y * z2;
- var zz = z * z2;
- var wx = w * x2;
- var wy = w * y2;
- var wz = w * z2;
- var sx = s.x;
- var sy = s.y;
- var sz = s.z;
-
- out.m00 = (1 - (yy + zz)) * sx;
- out.m01 = (xy + wz) * sx;
- out.m02 = (xz - wy) * sx;
- out.m03 = 0;
- out.m04 = (xy - wz) * sy;
- out.m05 = (1 - (xx + zz)) * sy;
- out.m06 = (yz + wx) * sy;
- out.m07 = 0;
- out.m08 = (xz + wy) * sz;
- out.m09 = (yz - wx) * sz;
- out.m10 = (1 - (xx + yy)) * sz;
- out.m11 = 0;
- out.m12 = v.x;
- out.m13 = v.y;
- out.m14 = v.z;
- out.m15 = 1;
-
- return out;
-};
-
-/**
- * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.translate(dest, vec);
- * mat4.translate(dest, origin);
- * let quatMat = mat4.create();
- * quat.toMat4(quat, quatMat);
- * mat4.multiply(dest, quatMat);
- * mat4.scale(dest, scale)
- * mat4.translate(dest, negativeOrigin);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {quat} q Rotation quaternion
- * @param {vec3} v Translation vector
- * @param {vec3} s Scaling vector
- * @param {vec3} o The origin vector around which to scale and rotate
- * @returns {mat4} out
- */
-mat4.fromRTSOrigin = function (out, q, v, s, o) {
- // Quaternion math
- var x = q.x, y = q.y, z = q.z, w = q.w;
- var x2 = x + x;
- var y2 = y + y;
- var z2 = z + z;
-
- var xx = x * x2;
- var xy = x * y2;
- var xz = x * z2;
- var yy = y * y2;
- var yz = y * z2;
- var zz = z * z2;
- var wx = w * x2;
- var wy = w * y2;
- var wz = w * z2;
-
- var sx = s.x;
- var sy = s.y;
- var sz = s.z;
-
- var ox = o.x;
- var oy = o.y;
- var oz = o.z;
-
- out.m00 = (1 - (yy + zz)) * sx;
- out.m01 = (xy + wz) * sx;
- out.m02 = (xz - wy) * sx;
- out.m03 = 0;
- out.m04 = (xy - wz) * sy;
- out.m05 = (1 - (xx + zz)) * sy;
- out.m06 = (yz + wx) * sy;
- out.m07 = 0;
- out.m08 = (xz + wy) * sz;
- out.m09 = (yz - wx) * sz;
- out.m10 = (1 - (xx + yy)) * sz;
- out.m11 = 0;
- out.m12 = v.x + ox - (out.m00 * ox + out.m04 * oy + out.m08 * oz);
- out.m13 = v.y + oy - (out.m01 * ox + out.m05 * oy + out.m09 * oz);
- out.m14 = v.z + oz - (out.m02 * ox + out.m06 * oy + out.m10 * oz);
- out.m15 = 1;
-
- return out;
-};
-
-/**
- * Calculates a 4x4 matrix from the given quaternion
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {quat} q Quaternion to create matrix from
- *
- * @returns {mat4} out
- */
-mat4.fromQuat = function (out, q) {
- var x = q.x, y = q.y, z = q.z, w = q.w;
- var x2 = x + x;
- var y2 = y + y;
- var z2 = z + z;
-
- var xx = x * x2;
- var yx = y * x2;
- var yy = y * y2;
- var zx = z * x2;
- var zy = z * y2;
- var zz = z * z2;
- var wx = w * x2;
- var wy = w * y2;
- var wz = w * z2;
-
- out.m00 = 1 - yy - zz;
- out.m01 = yx + wz;
- out.m02 = zx - wy;
- out.m03 = 0;
-
- out.m04 = yx - wz;
- out.m05 = 1 - xx - zz;
- out.m06 = zy + wx;
- out.m07 = 0;
-
- out.m08 = zx + wy;
- out.m09 = zy - wx;
- out.m10 = 1 - xx - yy;
- out.m11 = 0;
-
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = 0;
- out.m15 = 1;
-
- return out;
-};
-
-/**
- * Generates a frustum matrix with the given bounds
- *
- * @param {mat4} out mat4 frustum matrix will be written into
- * @param {Number} left Left bound of the frustum
- * @param {Number} right Right bound of the frustum
- * @param {Number} bottom Bottom bound of the frustum
- * @param {Number} top Top bound of the frustum
- * @param {Number} near Near bound of the frustum
- * @param {Number} far Far bound of the frustum
- * @returns {mat4} out
- */
-mat4.frustum = function (out, left, right, bottom, top, near, far) {
- var rl = 1 / (right - left);
- var tb = 1 / (top - bottom);
- var nf = 1 / (near - far);
-
- out.m00 = (near * 2) * rl;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 0;
- out.m05 = (near * 2) * tb;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = (right + left) * rl;
- out.m09 = (top + bottom) * tb;
- out.m10 = (far + near) * nf;
- out.m11 = -1;
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = (far * near * 2) * nf;
- out.m15 = 0;
- return out;
-};
-
-/**
- * Generates a perspective projection matrix with the given bounds
- *
- * @param {mat4} out mat4 frustum matrix will be written into
- * @param {number} fovy Vertical field of view in radians
- * @param {number} aspect Aspect ratio. typically viewport width/height
- * @param {number} near Near bound of the frustum
- * @param {number} far Far bound of the frustum
- * @returns {mat4} out
- */
-mat4.perspective = function (out, fovy, aspect, near, far) {
- var f = 1.0 / Math.tan(fovy / 2);
- var nf = 1 / (near - far);
-
- out.m00 = f / aspect;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 0;
- out.m05 = f;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 0;
- out.m09 = 0;
- out.m10 = (far + near) * nf;
- out.m11 = -1;
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = (2 * far * near) * nf;
- out.m15 = 0;
- return out;
-};
-
-/**
- * Generates a perspective projection matrix with the given field of view.
- * This is primarily useful for generating projection matrices to be used
- * with the still experiemental WebVR API.
- *
- * @param {mat4} out mat4 frustum matrix will be written into
- * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees
- * @param {number} near Near bound of the frustum
- * @param {number} far Far bound of the frustum
- * @returns {mat4} out
- */
-mat4.perspectiveFromFieldOfView = function (out, fov, near, far) {
- var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0);
- var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0);
- var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0);
- var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0);
- var xScale = 2.0 / (leftTan + rightTan);
- var yScale = 2.0 / (upTan + downTan);
-
- out.m00 = xScale;
- out.m01 = 0.0;
- out.m02 = 0.0;
- out.m03 = 0.0;
- out.m04 = 0.0;
- out.m05 = yScale;
- out.m06 = 0.0;
- out.m07 = 0.0;
- out.m08 = -((leftTan - rightTan) * xScale * 0.5);
- out.m09 = ((upTan - downTan) * yScale * 0.5);
- out.m10 = far / (near - far);
- out.m11 = -1.0;
- out.m12 = 0.0;
- out.m13 = 0.0;
- out.m14 = (far * near) / (near - far);
- out.m15 = 0.0;
- return out;
-};
-
-/**
- * Generates a orthogonal projection matrix with the given bounds
- *
- * @param {mat4} out mat4 frustum matrix will be written into
- * @param {number} left Left bound of the frustum
- * @param {number} right Right bound of the frustum
- * @param {number} bottom Bottom bound of the frustum
- * @param {number} top Top bound of the frustum
- * @param {number} near Near bound of the frustum
- * @param {number} far Far bound of the frustum
- * @returns {mat4} out
- */
-mat4.ortho = function (out, left, right, bottom, top, near, far) {
- var lr = 1 / (left - right);
- var bt = 1 / (bottom - top);
- var nf = 1 / (near - far);
- out.m00 = -2 * lr;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 0;
- out.m05 = -2 * bt;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 0;
- out.m09 = 0;
- out.m10 = 2 * nf;
- out.m11 = 0;
- out.m12 = (left + right) * lr;
- out.m13 = (top + bottom) * bt;
- out.m14 = (far + near) * nf;
- out.m15 = 1;
- return out;
-};
-
-/**
- * Generates a look-at matrix with the given eye position, focal point, and up axis
- *
- * @param {mat4} out mat4 frustum matrix will be written into
- * @param {vec3} eye Position of the viewer
- * @param {vec3} center Point the viewer is looking at
- * @param {vec3} up vec3 pointing up
- * @returns {mat4} out
- */
-mat4.lookAt = function (out, eye, center, up) {
- var x0, x1, x2, y0, y1, y2, z0, z1, z2, len;
- var eyex = eye.x;
- var eyey = eye.y;
- var eyez = eye.z;
- var upx = up.x;
- var upy = up.y;
- var upz = up.z;
- var centerx = center.x;
- var centery = center.y;
- var centerz = center.z;
-
- if (
- Math.abs(eyex - centerx) < EPSILON &&
- Math.abs(eyey - centery) < EPSILON &&
- Math.abs(eyez - centerz) < EPSILON
- ) {
- return mat4.identity(out);
- }
-
- z0 = eyex - centerx;
- z1 = eyey - centery;
- z2 = eyez - centerz;
-
- len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
- z0 *= len;
- z1 *= len;
- z2 *= len;
-
- x0 = upy * z2 - upz * z1;
- x1 = upz * z0 - upx * z2;
- x2 = upx * z1 - upy * z0;
- len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
- if (!len) {
- x0 = 0;
- x1 = 0;
- x2 = 0;
- } else {
- len = 1 / len;
- x0 *= len;
- x1 *= len;
- x2 *= len;
- }
-
- y0 = z1 * x2 - z2 * x1;
- y1 = z2 * x0 - z0 * x2;
- y2 = z0 * x1 - z1 * x0;
-
- len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
- if (!len) {
- y0 = 0;
- y1 = 0;
- y2 = 0;
- } else {
- len = 1 / len;
- y0 *= len;
- y1 *= len;
- y2 *= len;
- }
-
- out.m00 = x0;
- out.m01 = y0;
- out.m02 = z0;
- out.m03 = 0;
- out.m04 = x1;
- out.m05 = y1;
- out.m06 = z1;
- out.m07 = 0;
- out.m08 = x2;
- out.m09 = y2;
- out.m10 = z2;
- out.m11 = 0;
- out.m12 = -(x0 * eyex + x1 * eyey + x2 * eyez);
- out.m13 = -(y0 * eyex + y1 * eyey + y2 * eyez);
- out.m14 = -(z0 * eyex + z1 * eyey + z2 * eyez);
- out.m15 = 1;
-
- return out;
-};
-
-/**
- * Returns a string representation of a mat4
- *
- * @param {mat4} a matrix to represent as a string
- * @returns {String} string representation of the matrix
- */
-mat4.str = function (a) {
- return ("mat4(" + (a.m00) + ", " + (a.m01) + ", " + (a.m02) + ", " + (a.m03) + ", " + (a.m04) + ", " + (a.m05) + ", " + (a.m06) + ", " + (a.m07) + ", " + (a.m08) + ", " + (a.m09) + ", " + (a.m10) + ", " + (a.m11) + ", " + (a.m12) + ", " + (a.m13) + ", " + (a.m14) + ", " + (a.m15) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {mat4} m
- * @returns {array}
- */
-mat4.array = function (out, m) {
- out[0] = m.m00;
- out[1] = m.m01;
- out[2] = m.m02;
- out[3] = m.m03;
- out[4] = m.m04;
- out[5] = m.m05;
- out[6] = m.m06;
- out[7] = m.m07;
- out[8] = m.m08;
- out[9] = m.m09;
- out[10] = m.m10;
- out[11] = m.m11;
- out[12] = m.m12;
- out[13] = m.m13;
- out[14] = m.m14;
- out[15] = m.m15;
-
- return out;
-};
-
-/**
- * Returns Frobenius norm of a mat4
- *
- * @param {mat4} a the matrix to calculate Frobenius norm of
- * @returns {Number} Frobenius norm
- */
-mat4.frob = function (a) {
- return (Math.sqrt(Math.pow(a.m00, 2) + Math.pow(a.m01, 2) + Math.pow(a.m02, 2) + Math.pow(a.m03, 2) + Math.pow(a.m04, 2) + Math.pow(a.m05, 2) + Math.pow(a.m06, 2) + Math.pow(a.m07, 2) + Math.pow(a.m08, 2) + Math.pow(a.m09, 2) + Math.pow(a.m10, 2) + Math.pow(a.m11, 2) + Math.pow(a.m12, 2) + Math.pow(a.m13, 2) + Math.pow(a.m14, 2) + Math.pow(a.m15, 2)))
-};
-
-/**
- * Adds two mat4's
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the first operand
- * @param {mat4} b the second operand
- * @returns {mat4} out
- */
-mat4.add = function (out, a, b) {
- out.m00 = a.m00 + b.m00;
- out.m01 = a.m01 + b.m01;
- out.m02 = a.m02 + b.m02;
- out.m03 = a.m03 + b.m03;
- out.m04 = a.m04 + b.m04;
- out.m05 = a.m05 + b.m05;
- out.m06 = a.m06 + b.m06;
- out.m07 = a.m07 + b.m07;
- out.m08 = a.m08 + b.m08;
- out.m09 = a.m09 + b.m09;
- out.m10 = a.m10 + b.m10;
- out.m11 = a.m11 + b.m11;
- out.m12 = a.m12 + b.m12;
- out.m13 = a.m13 + b.m13;
- out.m14 = a.m14 + b.m14;
- out.m15 = a.m15 + b.m15;
- return out;
-};
-
-/**
- * Subtracts matrix b from matrix a
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the first operand
- * @param {mat4} b the second operand
- * @returns {mat4} out
- */
-mat4.subtract = function (out, a, b) {
- out.m00 = a.m00 - b.m00;
- out.m01 = a.m01 - b.m01;
- out.m02 = a.m02 - b.m02;
- out.m03 = a.m03 - b.m03;
- out.m04 = a.m04 - b.m04;
- out.m05 = a.m05 - b.m05;
- out.m06 = a.m06 - b.m06;
- out.m07 = a.m07 - b.m07;
- out.m08 = a.m08 - b.m08;
- out.m09 = a.m09 - b.m09;
- out.m10 = a.m10 - b.m10;
- out.m11 = a.m11 - b.m11;
- out.m12 = a.m12 - b.m12;
- out.m13 = a.m13 - b.m13;
- out.m14 = a.m14 - b.m14;
- out.m15 = a.m15 - b.m15;
- return out;
-};
-
-/**
- * Alias for {@link mat4.subtract}
- * @function
- */
-mat4.sub = mat4.subtract;
-
-/**
- * Multiply each element of the matrix by a scalar.
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the matrix to scale
- * @param {Number} b amount to scale the matrix's elements by
- * @returns {mat4} out
- */
-mat4.multiplyScalar = function (out, a, b) {
- out.m00 = a.m00 * b;
- out.m01 = a.m01 * b;
- out.m02 = a.m02 * b;
- out.m03 = a.m03 * b;
- out.m04 = a.m04 * b;
- out.m05 = a.m05 * b;
- out.m06 = a.m06 * b;
- out.m07 = a.m07 * b;
- out.m08 = a.m08 * b;
- out.m09 = a.m09 * b;
- out.m10 = a.m10 * b;
- out.m11 = a.m11 * b;
- out.m12 = a.m12 * b;
- out.m13 = a.m13 * b;
- out.m14 = a.m14 * b;
- out.m15 = a.m15 * b;
- return out;
-};
-
-/**
- * Adds two mat4's after multiplying each element of the second operand by a scalar value.
- *
- * @param {mat4} out the receiving vector
- * @param {mat4} a the first operand
- * @param {mat4} b the second operand
- * @param {Number} scale the amount to scale b's elements by before adding
- * @returns {mat4} out
- */
-mat4.multiplyScalarAndAdd = function (out, a, b, scale) {
- out.m00 = a.m00 + (b.m00 * scale);
- out.m01 = a.m01 + (b.m01 * scale);
- out.m02 = a.m02 + (b.m02 * scale);
- out.m03 = a.m03 + (b.m03 * scale);
- out.m04 = a.m04 + (b.m04 * scale);
- out.m05 = a.m05 + (b.m05 * scale);
- out.m06 = a.m06 + (b.m06 * scale);
- out.m07 = a.m07 + (b.m07 * scale);
- out.m08 = a.m08 + (b.m08 * scale);
- out.m09 = a.m09 + (b.m09 * scale);
- out.m10 = a.m10 + (b.m10 * scale);
- out.m11 = a.m11 + (b.m11 * scale);
- out.m12 = a.m12 + (b.m12 * scale);
- out.m13 = a.m13 + (b.m13 * scale);
- out.m14 = a.m14 + (b.m14 * scale);
- out.m15 = a.m15 + (b.m15 * scale);
- return out;
-};
-
-/**
- * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
- *
- * @param {mat4} a The first matrix.
- * @param {mat4} b The second matrix.
- * @returns {Boolean} True if the matrices are equal, false otherwise.
- */
-mat4.exactEquals = function (a, b) {
- return a.m00 === b.m00 && a.m01 === b.m01 && a.m02 === b.m02 && a.m03 === b.m03 &&
- a.m04 === b.m04 && a.m05 === b.m05 && a.m06 === b.m06 && a.m07 === b.m07 &&
- a.m08 === b.m08 && a.m09 === b.m09 && a.m10 === b.m10 && a.m11 === b.m11 &&
- a.m12 === b.m12 && a.m13 === b.m13 && a.m14 === b.m14 && a.m15 === b.m15;
-};
-
-/**
- * Returns whether or not the matrices have approximately the same elements in the same position.
- *
- * @param {mat4} a The first matrix.
- * @param {mat4} b The second matrix.
- * @returns {Boolean} True if the matrices are equal, false otherwise.
- */
-mat4.equals = function (a, b) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03,
- a4 = a.m04, a5 = a.m05, a6 = a.m06, a7 = a.m07,
- a8 = a.m08, a9 = a.m09, a10 = a.m10, a11 = a.m11,
- a12 = a.m12, a13 = a.m13, a14 = a.m14, a15 = a.m15;
-
- var b0 = b.m00, b1 = b.m01, b2 = b.m02, b3 = b.m03,
- b4 = b.m04, b5 = b.m05, b6 = b.m06, b7 = b.m07,
- b8 = b.m08, b9 = b.m09, b10 = b.m10, b11 = b.m11,
- b12 = b.m12, b13 = b.m13, b14 = b.m14, b15 = b.m15;
-
- return (
- Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
- Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
- Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&
- Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&
- Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&
- Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&
- Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) &&
- Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8)) &&
- Math.abs(a9 - b9) <= EPSILON * Math.max(1.0, Math.abs(a9), Math.abs(b9)) &&
- Math.abs(a10 - b10) <= EPSILON * Math.max(1.0, Math.abs(a10), Math.abs(b10)) &&
- Math.abs(a11 - b11) <= EPSILON * Math.max(1.0, Math.abs(a11), Math.abs(b11)) &&
- Math.abs(a12 - b12) <= EPSILON * Math.max(1.0, Math.abs(a12), Math.abs(b12)) &&
- Math.abs(a13 - b13) <= EPSILON * Math.max(1.0, Math.abs(a13), Math.abs(b13)) &&
- Math.abs(a14 - b14) <= EPSILON * Math.max(1.0, Math.abs(a14), Math.abs(b14)) &&
- Math.abs(a15 - b15) <= EPSILON * Math.max(1.0, Math.abs(a15), Math.abs(b15))
- );
-};
-
-var _tmp$8 = new Array(3);
-
-var _color3 = function _color3(r, g, b) {
- this.r = r;
- this.g = g;
- this.b = b;
-};
-
-_color3.prototype.toJSON = function toJSON () {
- _tmp$8[0] = this.r;
- _tmp$8[1] = this.g;
- _tmp$8[2] = this.b;
-
- return _tmp$8;
-};
-
-/**
- * @class Color
- * @name color3
- */
-var color3 = {};
-
-/**
- * Creates a new color
- *
- * @returns {color3} a new color
- */
-color3.create = function () {
- return new _color3(1, 1, 1);
-};
-
-/**
- * Creates a new color initialized with the given values
- *
- * @param {Number} r red component
- * @param {Number} g green component
- * @param {Number} b blue component
- * @returns {color3} a new color
- * @function
- */
-color3.new = function (r, g, b) {
- return new _color3(r, g, b);
-};
-
-/**
- * Creates a new color initialized with values from an existing quaternion
- *
- * @param {color3} a color to clone
- * @returns {color3} a new color
- * @function
- */
-color3.clone = function (a) {
- return new _color3(a.r, a.g, a.b, a.a);
-};
-
-/**
- * Copy the values from one color to another
- *
- * @param {color3} out the receiving color
- * @param {color3} a the source color
- * @returns {color3} out
- * @function
- */
-color3.copy = function (out, a) {
- out.r = a.r;
- out.g = a.g;
- out.b = a.b;
- return out;
-};
-
-/**
- * Set the components of a color to the given values
- *
- * @param {color3} out the receiving color
- * @param {Number} r red component
- * @param {Number} g green component
- * @param {Number} b blue component
- * @returns {color3} out
- * @function
- */
-color3.set = function (out, r, g, b) {
- out.r = r;
- out.g = g;
- out.b = b;
- return out;
-};
-
-/**
- * Set from hex
- *
- * @param {color3} out the receiving color
- * @param {Number} hex
- * @returns {color3} out
- * @function
- */
-color3.fromHex = function (out, hex) {
- var r = ((hex >> 16)) / 255.0;
- var g = ((hex >> 8) & 0xff) / 255.0;
- var b = ((hex) & 0xff) / 255.0;
-
- out.r = r;
- out.g = g;
- out.b = b;
- return out;
-};
-
-/**
- * Adds two color's
- *
- * @param {color3} out the receiving color
- * @param {color3} a the first operand
- * @param {color3} b the second operand
- * @returns {color3} out
- * @function
- */
-color3.add = function (out, a, b) {
- out.r = a.r + b.r;
- out.g = a.g + b.g;
- out.b = a.b + b.b;
- return out;
-};
-
-/**
- * Subtracts color b from color a
- *
- * @param {color3} out the receiving color
- * @param {color3} a the first operand
- * @param {color3} b the second operand
- * @returns {color3} out
- */
-color3.subtract = function (out, a, b) {
- out.r = a.r - b.r;
- out.g = a.g - b.g;
- out.b = a.b - b.b;
- return out;
-};
-
-/**
- * Alias for {@link color3.subtract}
- * @function
- */
-color3.sub = color3.subtract;
-
-/**
- * Multiplies two color's
- *
- * @param {color3} out the receiving color
- * @param {color3} a the first operand
- * @param {color3} b the second operand
- * @returns {color3} out
- * @function
- */
-color3.multiply = function (out, a, b) {
- out.r = a.r * b.r;
- out.g = a.g * b.g;
- out.b = a.b * b.b;
- return out;
-};
-
-/**
- * Alias for {@link color3.multiply}
- * @function
- */
-color3.mul = color3.multiply;
-
-/**
- * Divides two color's
- *
- * @param {color3} out the receiving vector
- * @param {color3} a the first operand
- * @param {color3} b the second operand
- * @returns {color3} out
- */
-color3.divide = function (out, a, b) {
- out.r = a.r / b.r;
- out.g = a.g / b.g;
- out.b = a.b / b.b;
- return out;
-};
-
-/**
- * Alias for {@link color3.divide}
- * @function
- */
-color3.div = color3.divide;
-
-
-/**
- * Scales a color by a scalar number
- *
- * @param {color3} out the receiving vector
- * @param {color3} a the vector to scale
- * @param {Number} b amount to scale the vector by
- * @returns {color3} out
- * @function
- */
-color3.scale = function (out, a, b) {
- out.r = a.r * b;
- out.g = a.g * b;
- out.b = a.b * b;
- return out;
-};
-
-/**
- * Performs a linear interpolation between two color's
- *
- * @param {color3} out the receiving color
- * @param {color3} a the first operand
- * @param {color3} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {color3} out
- * @function
- */
-color3.lerp = function (out, a, b, t) {
- var ar = a.r,
- ag = a.g,
- ab = a.b;
- out.r = ar + t * (b.r - ar);
- out.g = ag + t * (b.g - ag);
- out.b = ab + t * (b.b - ab);
- return out;
-};
-
-/**
- * Returns a string representation of a color
- *
- * @param {color3} a vector to represent as a string
- * @returns {String} string representation of the vector
- */
-color3.str = function (a) {
- return ("color3(" + (a.r) + ", " + (a.g) + ", " + (a.b) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {color3} a
- * @returns {array}
- */
-color3.array = function (out, a) {
- out[0] = a.r;
- out[1] = a.g;
- out[2] = a.b;
-
- return out;
-};
-
-/**
- * Returns whether or not the color have exactly the same elements in the same position (when compared with ===)
- *
- * @param {color3} a The first color3.
- * @param {color3} b The second color3.
- * @returns {Boolean} True if the colors are equal, false otherwise.
- */
-color3.exactEquals = function (a, b) {
- return a.r === b.r && a.g === b.g && a.b === b.b;
-};
-
-/**
- * Returns whether or not the colors have approximately the same elements in the same position.
- *
- * @param {color3} a The first color3.
- * @param {color3} b The second color3.
- * @returns {Boolean} True if the colors are equal, false otherwise.
- */
-color3.equals = function (a, b) {
- var a0 = a.r, a1 = a.g, a2 = a.b;
- var b0 = b.r, b1 = b.g, b2 = b.b;
- return (Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
- Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)));
-};
-
-/**
- * Returns the hex value
- *
- * @param {color3} a The color
- * @returns {Number}
- */
-color3.hex = function (a) {
- return (a.r * 255) << 16 | (a.g * 255) << 8 | (a.b * 255);
-};
-
-var _tmp$9 = new Array(4);
-
-var _color4 = function _color4(r, g, b, a) {
- this.r = r;
- this.g = g;
- this.b = b;
- this.a = a;
-};
-
-_color4.prototype.toJSON = function toJSON () {
- _tmp$9[0] = this.r;
- _tmp$9[1] = this.g;
- _tmp$9[2] = this.b;
- _tmp$9[3] = this.a;
-
- return _tmp$9;
-};
-
-/**
- * @class Color
- * @name color4
- */
-var color4 = {};
-
-/**
- * Creates a new color
- *
- * @returns {color4} a new color
- */
-color4.create = function () {
- return new _color4(1, 1, 1, 1);
-};
-
-/**
- * Creates a new color initialized with the given values
- *
- * @param {Number} r red component
- * @param {Number} g green component
- * @param {Number} b blue component
- * @param {Number} a alpha component
- * @returns {color4} a new color
- * @function
- */
-color4.new = function (r, g, b, a) {
- return new _color4(r, g, b, a);
-};
-
-/**
- * Creates a new color initialized with values from an existing quaternion
- *
- * @param {color4} a color to clone
- * @returns {color4} a new color
- * @function
- */
-color4.clone = function (a) {
- return new _color4(a.r, a.g, a.b, a.a);
-};
-
-/**
- * Copy the values from one color to another
- *
- * @param {color4} out the receiving color
- * @param {color4} a the source color
- * @returns {color4} out
- * @function
- */
-color4.copy = function (out, a) {
- out.r = a.r;
- out.g = a.g;
- out.b = a.b;
- out.a = a.a;
- return out;
-};
-
-/**
- * Set the components of a color to the given values
- *
- * @param {color4} out the receiving color
- * @param {Number} r red component
- * @param {Number} g green component
- * @param {Number} b blue component
- * @param {Number} a alpha component
- * @returns {color4} out
- * @function
- */
-color4.set = function (out, r, g, b, a) {
- out.r = r;
- out.g = g;
- out.b = b;
- out.a = a;
- return out;
-};
-
-/**
- * Set from hex
- *
- * @param {color4} out the receiving color
- * @param {Number} hex
- * @returns {color4} out
- * @function
- */
-color4.fromHex = function (out, hex) {
- var r = ((hex >> 24)) / 255.0;
- var g = ((hex >> 16) & 0xff) / 255.0;
- var b = ((hex >> 8) & 0xff) / 255.0;
- var a = ((hex) & 0xff) / 255.0;
-
- out.r = r;
- out.g = g;
- out.b = b;
- out.a = a;
- return out;
-};
-
-/**
- * Adds two color's
- *
- * @param {color4} out the receiving color
- * @param {color4} a the first operand
- * @param {color4} b the second operand
- * @returns {color4} out
- * @function
- */
-color4.add = function (out, a, b) {
- out.r = a.r + b.r;
- out.g = a.g + b.g;
- out.b = a.b + b.b;
- out.a = a.a + b.a;
- return out;
-};
-
-/**
- * Subtracts color b from color a
- *
- * @param {color4} out the receiving color
- * @param {color4} a the first operand
- * @param {color4} b the second operand
- * @returns {color4} out
- */
-color4.subtract = function (out, a, b) {
- out.r = a.r - b.r;
- out.g = a.g - b.g;
- out.b = a.b - b.b;
- out.a = a.a - b.a;
- return out;
-};
-
-/**
- * Alias for {@link color4.subtract}
- * @function
- */
-color4.sub = color4.subtract;
-
-/**
- * Multiplies two color's
- *
- * @param {color4} out the receiving color
- * @param {color4} a the first operand
- * @param {color4} b the second operand
- * @returns {color4} out
- * @function
- */
-color4.multiply = function (out, a, b) {
- out.r = a.r * b.r;
- out.g = a.g * b.g;
- out.b = a.b * b.b;
- out.a = a.a * b.a;
- return out;
-};
-
-/**
- * Alias for {@link color4.multiply}
- * @function
- */
-color4.mul = color4.multiply;
-
-/**
- * Divides two color's
- *
- * @param {color4} out the receiving vector
- * @param {color4} a the first operand
- * @param {color4} b the second operand
- * @returns {color4} out
- */
-color4.divide = function (out, a, b) {
- out.r = a.r / b.r;
- out.g = a.g / b.g;
- out.b = a.b / b.b;
- out.a = a.a / b.a;
- return out;
-};
-
-/**
- * Alias for {@link color4.divide}
- * @function
- */
-color4.div = color4.divide;
-
-
-/**
- * Scales a color by a scalar number
- *
- * @param {color4} out the receiving vector
- * @param {color4} a the vector to scale
- * @param {Number} b amount to scale the vector by
- * @returns {color4} out
- * @function
- */
-color4.scale = function (out, a, b) {
- out.r = a.r * b;
- out.g = a.g * b;
- out.b = a.b * b;
- out.a = a.a * b;
- return out;
-};
-
-/**
- * Performs a linear interpolation between two color's
- *
- * @param {color4} out the receiving color
- * @param {color4} a the first operand
- * @param {color4} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {color4} out
- * @function
- */
-color4.lerp = function (out, a, b, t) {
- var ar = a.r,
- ag = a.g,
- ab = a.b,
- aa = a.a;
- out.r = ar + t * (b.r - ar);
- out.g = ag + t * (b.g - ag);
- out.b = ab + t * (b.b - ab);
- out.a = aa + t * (b.a - aa);
- return out;
-};
-
-/**
- * Returns a string representation of a color
- *
- * @param {color4} a vector to represent as a string
- * @returns {String} string representation of the vector
- */
-color4.str = function (a) {
- return ("color4(" + (a.r) + ", " + (a.g) + ", " + (a.b) + ", " + (a.a) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {color4} a
- * @returns {array}
- */
-color4.array = function (out, a) {
- out[0] = a.r;
- out[1] = a.g;
- out[2] = a.b;
- out[3] = a.a;
-
- return out;
-};
-
-/**
- * Returns whether or not the color have exactly the same elements in the same position (when compared with ===)
- *
- * @param {color4} a The first color4.
- * @param {color4} b The second color4.
- * @returns {Boolean} True if the colors are equal, false otherwise.
- */
-color4.exactEquals = function (a, b) {
- return a.r === b.r && a.g === b.g && a.b === b.b && a.a === b.a;
-};
-
-/**
- * Returns whether or not the colors have approximately the same elements in the same position.
- *
- * @param {color4} a The first color4.
- * @param {color4} b The second color4.
- * @returns {Boolean} True if the colors are equal, false otherwise.
- */
-color4.equals = function (a, b) {
- var a0 = a.r, a1 = a.g, a2 = a.b, a3 = a.a;
- var b0 = b.r, b1 = b.g, b2 = b.b, b3 = b.a;
- return (Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
- Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
- Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)));
-};
-
-/**
- * Returns the hex value
- *
- * @param {color4} a The color
- * @returns {Number}
- */
-color4.hex = function (a) {
- return ((a.r * 255) << 24 | (a.g * 255) << 16 | (a.b * 255) << 8 | a.a * 255) >>> 0;
-};
-
-// NOTE: there is no syntax for: export {* as bits} from './lib/bits';
-var bits = bits_;
-
-
-
-var math = Object.freeze({
- bits: bits,
- vec2: vec2,
- vec3: vec3,
- vec4: vec4,
- quat: quat,
- mat2: mat2,
- mat23: mat23,
- mat3: mat3,
- mat4: mat4,
- color3: color3,
- color4: color4,
- EPSILON: EPSILON,
- equals: equals,
- approx: approx,
- clamp: clamp,
- clamp01: clamp01,
- lerp: lerp,
- toRadian: toRadian,
- toDegree: toDegree,
- random: random,
- randomRange: randomRange,
- randomRangeInt: randomRangeInt,
- nextPow2: nextPow2
-});
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var Device = function Device(canvasEL) {
- var ctx;
-
- try {
- ctx = canvasEL.getContext('2d');
- } catch (err) {
- console.error(err);
- return;
- }
-
- // statics
- this._canvas = canvasEL;
- this._ctx = ctx;
- this._caps = {}; // capability
- this._stats = {
- drawcalls: 0,
- };
-
- // runtime
- this._vx = this._vy = this._vw = this._vh = 0;
- this._sx = this._sy = this._sw = this._sh = 0;
-};
-
-Device.prototype._restoreTexture = function _restoreTexture (unit) {
-};
-
-// ===============================
-// Immediate Settings
-// ===============================
-
-/**
- * @method setViewport
- * @param {Number} x
- * @param {Number} y
- * @param {Number} w
- * @param {Number} h
- */
-Device.prototype.setViewport = function setViewport (x, y, w, h) {
- if (
- this._vx !== x ||
- this._vy !== y ||
- this._vw !== w ||
- this._vh !== h
- ) {
- this._vx = x;
- this._vy = y;
- this._vw = w;
- this._vh = h;
- }
-};
-
-/**
- * @method setScissor
- * @param {Number} x
- * @param {Number} y
- * @param {Number} w
- * @param {Number} h
- */
-Device.prototype.setScissor = function setScissor (x, y, w, h) {
- if (
- this._sx !== x ||
- this._sy !== y ||
- this._sw !== w ||
- this._sh !== h
- ) {
- this._sx = x;
- this._sy = y;
- this._sw = w;
- this._sh = h;
- }
-};
-
-Device.prototype.clear = function clear (color) {
- var ctx = this._ctx;
- ctx.clearRect(this._vx, this._vy, this._vw, this._vh);
- if (color && (color[0] !== 0 || color[1] !== 0 || color[2] !== 0)) {
- ctx.fillStyle = 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] +')';
- ctx.globalAlpha = color[3];
- ctx.fillRect(this._vx, this._vy, this._vw, this._vh);
- }
-};
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var Texture2D = function Texture2D(device, options) {
- this._device = device;
-
- this._width = 4;
- this._height = 4;
-
- this._image = null;
-
- if (options) {
- if (options.width !== undefined) {
- this._width = options.width;
- }
- if (options.height !== undefined) {
- this._height = options.height;
- }
-
- this.updateImage(options);
- }
-};
-
-Texture2D.prototype.update = function update (options) {
- this.updateImage(options);
-};
-
-Texture2D.prototype.updateImage = function updateImage (options) {
- if (options.images && options.images[0]) {
- var image = options.images[0];
- if (image && image !== this._image) {
- this._image = image;
- }
- }
-};
-
-Texture2D.prototype.destroy = function destroy () {
- this._image = null;
-};
-
-var canvas = {
- Device: Device,
- Texture2D: Texture2D
-};
-
-// intenral
-// deps
-var Texture2D$2 = canvas.Texture2D;
-var Device$2 = canvas.Device;
-var gfx = {};
-
-var renderEngine = {
- // core classes
- Device: Device$2,
- Texture2D: Texture2D$2,
-
- // Canvas render support
- canvas: canvas,
-
- // render scene
- RenderData: RenderData,
-
- // memop
- RecyclePool: RecyclePool,
- Pool: Pool,
-
- // modules
- math: math,
- gfx: gfx
-};
-
-module.exports = renderEngine;
diff --git a/cocos2d/core/renderer/render-engine.js b/cocos2d/core/renderer/render-engine.js
deleted file mode 100644
index ca2ce23b8ef..00000000000
--- a/cocos2d/core/renderer/render-engine.js
+++ /dev/null
@@ -1,14781 +0,0 @@
-
-/****************************************************************************
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- render-engine v1.2.0
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-
-'use strict';
-
-var _d2r = Math.PI / 180.0;
-var _r2d = 180.0 / Math.PI;
-
-/**
- * @property {number} EPSILON
- */
-var EPSILON = 0.000001;
-
-/**
- * Tests whether or not the arguments have approximately the same value, within an absolute
- * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less
- * than or equal to 1.0, and a relative tolerance is used for larger values)
- *
- * @param {Number} a The first number to test.
- * @param {Number} b The second number to test.
- * @returns {Boolean} True if the numbers are approximately equal, false otherwise.
- */
-function equals(a, b) {
- return Math.abs(a - b) <= EPSILON * Math.max(1.0, Math.abs(a), Math.abs(b));
-}
-
-/**
- * Tests whether or not the arguments have approximately the same value by given maxDiff
- *
- * @param {Number} a The first number to test.
- * @param {Number} b The second number to test.
- * @param {Number} maxDiff Maximum difference.
- * @returns {Boolean} True if the numbers are approximately equal, false otherwise.
- */
-function approx(a, b, maxDiff) {
- maxDiff = maxDiff || EPSILON;
- return Math.abs(a - b) <= maxDiff;
-}
-
-/**
- * Clamps a value between a minimum float and maximum float value.
- *
- * @method clamp
- * @param {number} val
- * @param {number} min
- * @param {number} max
- * @return {number}
- */
-function clamp(val, min, max) {
- return val < min ? min : val > max ? max : val;
-}
-
-/**
- * Clamps a value between 0 and 1.
- *
- * @method clamp01
- * @param {number} val
- * @return {number}
- */
-function clamp01(val) {
- return val < 0 ? 0 : val > 1 ? 1 : val;
-}
-
-/**
- * @method lerp
- * @param {number} from
- * @param {number} to
- * @param {number} ratio - the interpolation coefficient
- * @return {number}
- */
-function lerp(from, to, ratio) {
- return from + (to - from) * ratio;
-}
-
-/**
-* Convert Degree To Radian
-*
-* @param {Number} a Angle in Degrees
-*/
-function toRadian(a) {
- return a * _d2r;
-}
-
-/**
-* Convert Radian To Degree
-*
-* @param {Number} a Angle in Radian
-*/
-function toDegree(a) {
- return a * _r2d;
-}
-
-/**
-* @method random
-*/
-var random = Math.random;
-
-/**
- * Returns a floating-point random number between min (inclusive) and max (exclusive).
- *
- * @method randomRange
- * @param {number} min
- * @param {number} max
- * @return {number} the random number
- */
-function randomRange(min, max) {
- return Math.random() * (max - min) + min;
-}
-
-/**
- * Returns a random integer between min (inclusive) and max (exclusive).
- *
- * @method randomRangeInt
- * @param {number} min
- * @param {number} max
- * @return {number} the random integer
- */
-function randomRangeInt(min, max) {
- return Math.floor(randomRange(min, max));
-}
-
-/**
- * Returns the next power of two for the value
- *
- * @method nextPow2
- * @param {number} val
- * @return {number} the the next power of two
- */
-function nextPow2(val) {
- --val;
- val = (val >> 1) | val;
- val = (val >> 2) | val;
- val = (val >> 4) | val;
- val = (val >> 8) | val;
- val = (val >> 16) | val;
- ++val;
-
- return val;
-}
-
-/**
- * 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;
-var INT_MAX = 0x7fffffff;
-var INT_MIN = -1<<(INT_BITS-1);
-
-/**
- * Returns -1, 0, +1 depending on sign of x
- *
- * @param {number} v
- * @returns {number}
- */
-function sign(v) {
- return (v > 0) - (v < 0);
-}
-
-/**
- * Computes absolute value of integer
- *
- * @param {number} v
- * @returns {number}
- */
-function abs(v) {
- var mask = v >> (INT_BITS-1);
- return (v ^ mask) - mask;
-}
-
-/**
- * Computes minimum of integers x and y
- *
- * @param {number} x
- * @param {number} y
- * @returns {number}
- */
-function min(x, y) {
- return y ^ ((x ^ y) & -(x < y));
-}
-
-/**
- * Computes maximum of integers x and y
- *
- * @param {number} x
- * @param {number} y
- * @returns {number}
- */
-function max(x, y) {
- return x ^ ((x ^ y) & -(x < y));
-}
-
-/**
- * Checks if a number is a power of two
- *
- * @param {number} v
- * @returns {boolean}
- */
-function isPow2(v) {
- return !(v & (v-1)) && (!!v);
-}
-
-/**
- * Computes log base 2 of v
- *
- * @param {number} v
- * @returns {number}
- */
-function log2(v) {
- var r, shift;
- r = (v > 0xFFFF) << 4; v >>>= r;
- shift = (v > 0xFF ) << 3; v >>>= shift; r |= shift;
- shift = (v > 0xF ) << 2; v >>>= shift; r |= shift;
- shift = (v > 0x3 ) << 1; v >>>= shift; r |= shift;
- return r | (v >> 1);
-}
-
-/**
- * Computes log base 10 of v
- *
- * @param {number} v
- * @returns {number}
- */
-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
- *
- * @param {number} v
- * @returns {number}
- */
-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
- *
- * @param {number} v
- * @returns {number}
- */
-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
- *
- * @param {number} v
- * @returns {number}
- */
-function nextPow2$1(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
- *
- * @param {number} v
- * @returns {number}
- */
-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
- *
- * @param {number} v
- * @returns {number}
- */
-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
- *
- * @param {number} v
- * @returns {number}
- */
-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
- *
- * @param {number} x
- * @param {number} y
- * @returns {number}
- */
-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
- *
- * @param {number} v
- * @param {number} n
- * @returns {number}
- */
-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
- *
- * @param {number} x
- * @param {number} y
- * @param {number} z
- * @returns {number}
- */
-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
- *
- * @param {number} v
- * @param {number} n
- * @returns {number}
- */
-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)
- *
- * @param {number} v
- * @returns {number}
- */
-function nextCombination(v) {
- var t = v | (v - 1);
- return (t + 1) | (((~t & -~t) - 1) >>> (countTrailingZeros(v) + 1));
-}
-
-var bits_ = Object.freeze({
- INT_BITS: INT_BITS,
- INT_MAX: INT_MAX,
- INT_MIN: INT_MIN,
- sign: sign,
- abs: abs,
- min: min,
- max: max,
- isPow2: isPow2,
- log2: log2,
- log10: log10,
- popCount: popCount,
- countTrailingZeros: countTrailingZeros,
- nextPow2: nextPow2$1,
- prevPow2: prevPow2,
- parity: parity,
- reverse: reverse,
- interleave2: interleave2,
- deinterleave2: deinterleave2,
- interleave3: interleave3,
- deinterleave3: deinterleave3,
- nextCombination: nextCombination
-});
-
-var _tmp = new Array(2);
-
-var _vec2 = function _vec2(x, y) {
- this.x = x;
- this.y = y;
-};
-
-_vec2.prototype.toJSON = function toJSON () {
- _tmp[0] = this.x;
- _tmp[1] = this.y;
-
- return _tmp;
-};
-
-/**
- * @class 2 Dimensional Vector
- * @name vec2
- */
-var vec2 = {};
-
-/**
- * Creates a new, empty vec2
- *
- * @returns {vec2} a new 2D vector
- */
-vec2.create = function () {
- return new _vec2(0, 0);
-};
-
-/**
- * Creates a new vec2 initialized with the given values
- *
- * @param {Number} x X component
- * @param {Number} y Y component
- * @returns {vec2} a new 2D vector
- */
-vec2.new = function (x, y) {
- return new _vec2(x, y);
-};
-
-/**
- * Creates a new vec2 initialized with values from an existing vector
- *
- * @param {vec2} a vector to clone
- * @returns {vec2} a new 2D vector
- */
-vec2.clone = function (a) {
- return new _vec2(a.x, a.y);
-};
-
-/**
- * Copy the values from one vec2 to another
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the source vector
- * @returns {vec2} out
- */
-vec2.copy = function (out, a) {
- out.x = a.x;
- out.y = a.y;
- return out;
-};
-
-/**
- * Set the components of a vec2 to the given values
- *
- * @param {vec2} out the receiving vector
- * @param {Number} x X component
- * @param {Number} y Y component
- * @returns {vec2} out
- */
-vec2.set = function (out, x, y) {
- out.x = x;
- out.y = y;
- return out;
-};
-
-/**
- * Adds two vec2's
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
- */
-vec2.add = function (out, a, b) {
- out.x = a.x + b.x;
- out.y = a.y + b.y;
- return out;
-};
-
-/**
- * Subtracts vector b from vector a
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
- */
-vec2.subtract = function (out, a, b) {
- out.x = a.x - b.x;
- out.y = a.y - b.y;
- return out;
-};
-
-/**
- * Alias for {@link vec2.subtract}
- * @function
- */
-vec2.sub = vec2.subtract;
-
-/**
- * Multiplies two vec2's
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
- */
-vec2.multiply = function (out, a, b) {
- out.x = a.x * b.x;
- out.y = a.y * b.y;
- return out;
-};
-
-/**
- * Alias for {@link vec2.multiply}
- * @function
- */
-vec2.mul = vec2.multiply;
-
-/**
- * Divides two vec2's
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
- */
-vec2.divide = function (out, a, b) {
- out.x = a.x / b.x;
- out.y = a.y / b.y;
- return out;
-};
-
-/**
- * Alias for {@link vec2.divide}
- * @function
- */
-vec2.div = vec2.divide;
-
-/**
- * Math.ceil the components of a vec2
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to ceil
- * @returns {vec2} out
- */
-vec2.ceil = function (out, a) {
- out.x = Math.ceil(a.x);
- out.y = Math.ceil(a.y);
- return out;
-};
-
-/**
- * Math.floor the components of a vec2
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to floor
- * @returns {vec2} out
- */
-vec2.floor = function (out, a) {
- out.x = Math.floor(a.x);
- out.y = Math.floor(a.y);
- return out;
-};
-
-/**
- * Returns the minimum of two vec2's
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
- */
-vec2.min = function (out, a, b) {
- out.x = Math.min(a.x, b.x);
- out.y = Math.min(a.y, b.y);
- return out;
-};
-
-/**
- * Returns the maximum of two vec2's
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
- */
-vec2.max = function (out, a, b) {
- out.x = Math.max(a.x, b.x);
- out.y = Math.max(a.y, b.y);
- return out;
-};
-
-/**
- * Math.round the components of a vec2
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to round
- * @returns {vec2} out
- */
-vec2.round = function (out, a) {
- out.x = Math.round(a.x);
- out.y = Math.round(a.y);
- return out;
-};
-
-/**
- * Scales a vec2 by a scalar number
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the vector to scale
- * @param {Number} b amount to scale the vector by
- * @returns {vec2} out
- */
-vec2.scale = function (out, a, b) {
- out.x = a.x * b;
- out.y = a.y * b;
- return out;
-};
-
-/**
- * Adds two vec2's after scaling the second operand by a scalar value
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @param {Number} scale the amount to scale b by before adding
- * @returns {vec2} out
- */
-vec2.scaleAndAdd = function (out, a, b, scale) {
- out.x = a.x + (b.x * scale);
- out.y = a.y + (b.y * scale);
- return out;
-};
-
-/**
- * Calculates the euclidian distance between two vec2's
- *
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {Number} distance between a and b
- */
-vec2.distance = function (a, b) {
- var x = b.x - a.x,
- y = b.y - a.y;
- return Math.sqrt(x * x + y * y);
-};
-
-/**
- * Alias for {@link vec2.distance}
- * @function
- */
-vec2.dist = vec2.distance;
-
-/**
- * Calculates the squared euclidian distance between two vec2's
- *
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {Number} squared distance between a and b
- */
-vec2.squaredDistance = function (a, b) {
- var x = b.x - a.x,
- y = b.y - a.y;
- return x * x + y * y;
-};
-
-/**
- * Alias for {@link vec2.squaredDistance}
- * @function
- */
-vec2.sqrDist = vec2.squaredDistance;
-
-/**
- * Calculates the length of a vec2
- *
- * @param {vec2} a vector to calculate length of
- * @returns {Number} length of a
- */
-vec2.length = function (a) {
- var x = a.x,
- y = a.y;
- return Math.sqrt(x * x + y * y);
-};
-
-/**
- * Alias for {@link vec2.length}
- * @function
- */
-vec2.len = vec2.length;
-
-/**
- * Calculates the squared length of a vec2
- *
- * @param {vec2} a vector to calculate squared length of
- * @returns {Number} squared length of a
- */
-vec2.squaredLength = function (a) {
- var x = a.x,
- y = a.y;
- return x * x + y * y;
-};
-
-/**
- * Alias for {@link vec2.squaredLength}
- * @function
- */
-vec2.sqrLen = vec2.squaredLength;
-
-/**
- * Negates the components of a vec2
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to negate
- * @returns {vec2} out
- */
-vec2.negate = function (out, a) {
- out.x = -a.x;
- out.y = -a.y;
- return out;
-};
-
-/**
- * Returns the inverse of the components of a vec2
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to invert
- * @returns {vec2} out
- */
-vec2.inverse = function (out, a) {
- out.x = 1.0 / a.x;
- out.y = 1.0 / a.y;
- return out;
-};
-
-/**
- * Returns the inverse of the components of a vec2 safely
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to invert
- * @returns {vec2} out
- */
-vec2.inverseSafe = function (out, a) {
- var x = a.x,
- y = a.y;
-
- if (Math.abs(x) < EPSILON) {
- out.x = 0;
- } else {
- out.x = 1.0 / x;
- }
-
- if (Math.abs(y) < EPSILON) {
- out.y = 0;
- } else {
- out.y = 1.0 / a.y;
- }
-
- return out;
-};
-
-/**
- * Normalize a vec2
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to normalize
- * @returns {vec2} out
- */
-vec2.normalize = function (out, a) {
- var x = a.x,
- y = a.y;
- var len = x * x + y * y;
- if (len > 0) {
- //TODO: evaluate use of glm_invsqrt here?
- len = 1 / Math.sqrt(len);
- out.x = a.x * len;
- out.y = a.y * len;
- }
- return out;
-};
-
-/**
- * Calculates the dot product of two vec2's
- *
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {Number} dot product of a and b
- */
-vec2.dot = function (a, b) {
- return a.x * b.x + a.y * b.y;
-};
-
-/**
- * Computes the cross product of two vec2's
- * Note that the cross product must by definition produce a 3D vector
- *
- * @param {vec3} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec3} out
- */
-vec2.cross = function (out, a, b) {
- var z = a.x * b.y - a.y * b.x;
- out.x = out.y = 0;
- out.z = z;
- return out;
-};
-
-/**
- * Performs a linear interpolation between two vec2's
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {vec2} out
- */
-vec2.lerp = function (out, a, b, t) {
- var ax = a.x,
- ay = a.y;
- out.x = ax + t * (b.x - ax);
- out.y = ay + t * (b.y - ay);
- return out;
-};
-
-/**
- * Generates a random vector with the given scale
- *
- * @param {vec2} out the receiving vector
- * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
- * @returns {vec2} out
- */
-vec2.random = function (out, scale) {
- scale = scale || 1.0;
- var r = random() * 2.0 * Math.PI;
- out.x = Math.cos(r) * scale;
- out.y = Math.sin(r) * scale;
- return out;
-};
-
-/**
- * Transforms the vec2 with a mat2
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the vector to transform
- * @param {mat2} m matrix to transform with
- * @returns {vec2} out
- */
-vec2.transformMat2 = function (out, a, m) {
- var x = a.x,
- y = a.y;
- out.x = m.m00 * x + m.m02 * y;
- out.y = m.m01 * x + m.m03 * y;
- return out;
-};
-
-/**
- * Transforms the vec2 with a mat23
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the vector to transform
- * @param {mat23} m matrix to transform with
- * @returns {vec2} out
- */
-vec2.transformMat23 = function (out, a, m) {
- var x = a.x,
- y = a.y;
- out.x = m.m00 * x + m.m02 * y + m.m04;
- out.y = m.m01 * x + m.m03 * y + m.m05;
- return out;
-};
-
-/**
- * Transforms the vec2 with a mat3
- * 3rd vector component is implicitly '1'
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the vector to transform
- * @param {mat3} m matrix to transform with
- * @returns {vec2} out
- */
-vec2.transformMat3 = function (out, a, m) {
- var x = a.x,
- y = a.y;
- out.x = m.m00 * x + m.m03 * y + m.m06;
- out.y = m.m01 * x + m.m04 * y + m.m07;
- return out;
-};
-
-/**
- * Transforms the vec2 with a mat4
- * 3rd vector component is implicitly '0'
- * 4th vector component is implicitly '1'
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the vector to transform
- * @param {mat4} m matrix to transform with
- * @returns {vec2} out
- */
-vec2.transformMat4 = function (out, a, m) {
- var x = a.x,
- y = a.y;
- out.x = m.m00 * x + m.m04 * y + m.m12;
- out.y = m.m01 * x + m.m05 * y + m.m13;
- return out;
-};
-
-/**
- * Perform some operation over an array of vec2s.
- *
- * @param {Array} a the array of vectors to iterate over
- * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
- * @param {Number} offset Number of elements to skip at the beginning of the array
- * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
- * @param {Function} fn Function to call for each vector in the array
- * @param {Object} [arg] additional argument to pass to fn
- * @returns {Array} a
- * @function
- */
-vec2.forEach = (function () {
- var vec = vec2.create();
-
- return function (a, stride, offset, count, fn, arg) {
- var i, l;
- if (!stride) {
- stride = 2;
- }
-
- if (!offset) {
- offset = 0;
- }
-
- if (count) {
- l = Math.min((count * stride) + offset, a.length);
- } else {
- l = a.length;
- }
-
- for (i = offset; i < l; i += stride) {
- vec.x = a[i]; vec.y = a[i + 1];
- fn(vec, vec, arg);
- a[i] = vec.x; a[i + 1] = vec.y;
- }
-
- return a;
- };
-})();
-
-/**
- * Returns a string representation of a vector
- *
- * @param {vec2} a vector to represent as a string
- * @returns {String} string representation of the vector
- */
-vec2.str = function (a) {
- return ("vec2(" + (a.x) + ", " + (a.y) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {vec2} v
- * @returns {array}
- */
-vec2.array = function (out, v) {
- out[0] = v.x;
- out[1] = v.y;
-
- return out;
-};
-
-/**
- * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)
- *
- * @param {vec2} a The first vector.
- * @param {vec2} b The second vector.
- * @returns {Boolean} True if the vectors are equal, false otherwise.
- */
-vec2.exactEquals = function (a, b) {
- return a.x === b.x && a.y === b.y;
-};
-
-/**
- * Returns whether or not the vectors have approximately the same elements in the same position.
- *
- * @param {vec2} a The first vector.
- * @param {vec2} b The second vector.
- * @returns {Boolean} True if the vectors are equal, false otherwise.
- */
-vec2.equals = function (a, b) {
- var a0 = a.x, a1 = a.y;
- var b0 = b.x, b1 = b.y;
- return (Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)));
-};
-
-var _tmp$1 = new Array(3);
-
-var _vec3 = function _vec3(x, y, z) {
- this.x = x;
- this.y = y;
- this.z = z;
-};
-
-_vec3.prototype.toJSON = function toJSON () {
- _tmp$1[0] = this.x;
- _tmp$1[1] = this.y;
- _tmp$1[2] = this.z;
-
- return _tmp$1;
-};
-
-/**
- * @class 3 Dimensional Vector
- * @name vec3
- */
-var vec3 = {};
-
-/**
- * Creates a new, empty vec3
- *
- * @returns {vec3} a new 3D vector
- */
-vec3.create = function () {
- return new _vec3(0, 0, 0);
-};
-
-/**
- * Creates a new vec3 initialized with the given values
- *
- * @param {Number} x X component
- * @param {Number} y Y component
- * @param {Number} z Z component
- * @returns {vec3} a new 3D vector
- */
-vec3.new = function (x, y, z) {
- return new _vec3(x, y, z);
-};
-
-/**
- * Creates a new vec3 initialized with values from an existing vector
- *
- * @param {vec3} a vector to clone
- * @returns {vec3} a new 3D vector
- */
-vec3.clone = function (a) {
- return new _vec3(a.x, a.y, a.z);
-};
-
-/**
- * Copy the values from one vec3 to another
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the source vector
- * @returns {vec3} out
- */
-vec3.copy = function (out, a) {
- out.x = a.x;
- out.y = a.y;
- out.z = a.z;
- return out;
-};
-
-/**
- * Set the components of a vec3 to the given values
- *
- * @param {vec3} out the receiving vector
- * @param {Number} x X component
- * @param {Number} y Y component
- * @param {Number} z Z component
- * @returns {vec3} out
- */
-vec3.set = function (out, x, y, z) {
- out.x = x;
- out.y = y;
- out.z = z;
- return out;
-};
-
-/**
- * Adds two vec3's
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.add = function (out, a, b) {
- out.x = a.x + b.x;
- out.y = a.y + b.y;
- out.z = a.z + b.z;
- return out;
-};
-
-/**
- * Subtracts vector b from vector a
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.subtract = function (out, a, b) {
- out.x = a.x - b.x;
- out.y = a.y - b.y;
- out.z = a.z - b.z;
- return out;
-};
-
-/**
- * Alias for {@link vec3.subtract}
- * @function
- */
-vec3.sub = vec3.subtract;
-
-/**
- * Multiplies two vec3's
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.multiply = function (out, a, b) {
- out.x = a.x * b.x;
- out.y = a.y * b.y;
- out.z = a.z * b.z;
- return out;
-};
-
-/**
- * Alias for {@link vec3.multiply}
- * @function
- */
-vec3.mul = vec3.multiply;
-
-/**
- * Divides two vec3's
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.divide = function (out, a, b) {
- out.x = a.x / b.x;
- out.y = a.y / b.y;
- out.z = a.z / b.z;
- return out;
-};
-
-/**
- * Alias for {@link vec3.divide}
- * @function
- */
-vec3.div = vec3.divide;
-
-/**
- * Math.ceil the components of a vec3
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a vector to ceil
- * @returns {vec3} out
- */
-vec3.ceil = function (out, a) {
- out.x = Math.ceil(a.x);
- out.y = Math.ceil(a.y);
- out.z = Math.ceil(a.z);
- return out;
-};
-
-/**
- * Math.floor the components of a vec3
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a vector to floor
- * @returns {vec3} out
- */
-vec3.floor = function (out, a) {
- out.x = Math.floor(a.x);
- out.y = Math.floor(a.y);
- out.z = Math.floor(a.z);
- return out;
-};
-
-/**
- * Returns the minimum of two vec3's
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.min = function (out, a, b) {
- out.x = Math.min(a.x, b.x);
- out.y = Math.min(a.y, b.y);
- out.z = Math.min(a.z, b.z);
- return out;
-};
-
-/**
- * Returns the maximum of two vec3's
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.max = function (out, a, b) {
- out.x = Math.max(a.x, b.x);
- out.y = Math.max(a.y, b.y);
- out.z = Math.max(a.z, b.z);
- return out;
-};
-
-/**
- * Math.round the components of a vec3
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a vector to round
- * @returns {vec3} out
- */
-vec3.round = function (out, a) {
- out.x = Math.round(a.x);
- out.y = Math.round(a.y);
- out.z = Math.round(a.z);
- return out;
-};
-
-/**
- * Scales a vec3 by a scalar number
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the vector to scale
- * @param {Number} b amount to scale the vector by
- * @returns {vec3} out
- */
-vec3.scale = function (out, a, b) {
- out.x = a.x * b;
- out.y = a.y * b;
- out.z = a.z * b;
- return out;
-};
-
-/**
- * Adds two vec3's after scaling the second operand by a scalar value
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @param {Number} scale the amount to scale b by before adding
- * @returns {vec3} out
- */
-vec3.scaleAndAdd = function (out, a, b, scale) {
- out.x = a.x + (b.x * scale);
- out.y = a.y + (b.y * scale);
- out.z = a.z + (b.z * scale);
- return out;
-};
-
-/**
- * Calculates the euclidian distance between two vec3's
- *
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {Number} distance between a and b
- */
-vec3.distance = function (a, b) {
- var x = b.x - a.x,
- y = b.y - a.y,
- z = b.z - a.z;
- return Math.sqrt(x * x + y * y + z * z);
-};
-
-/**
- * Alias for {@link vec3.distance}
- * @function
- */
-vec3.dist = vec3.distance;
-
-/**
- * Calculates the squared euclidian distance between two vec3's
- *
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {Number} squared distance between a and b
- */
-vec3.squaredDistance = function (a, b) {
- var x = b.x - a.x,
- y = b.y - a.y,
- z = b.z - a.z;
- return x * x + y * y + z * z;
-};
-
-/**
- * Alias for {@link vec3.squaredDistance}
- * @function
- */
-vec3.sqrDist = vec3.squaredDistance;
-
-/**
- * Calculates the length of a vec3
- *
- * @param {vec3} a vector to calculate length of
- * @returns {Number} length of a
- */
-vec3.length = function (a) {
- var x = a.x,
- y = a.y,
- z = a.z;
- return Math.sqrt(x * x + y * y + z * z);
-};
-
-/**
- * Alias for {@link vec3.length}
- * @function
- */
-vec3.len = vec3.length;
-
-/**
- * Calculates the squared length of a vec3
- *
- * @param {vec3} a vector to calculate squared length of
- * @returns {Number} squared length of a
- */
-vec3.squaredLength = function (a) {
- var x = a.x,
- y = a.y,
- z = a.z;
- return x * x + y * y + z * z;
-};
-
-/**
- * Alias for {@link vec3.squaredLength}
- * @function
- */
-vec3.sqrLen = vec3.squaredLength;
-
-/**
- * Negates the components of a vec3
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a vector to negate
- * @returns {vec3} out
- */
-vec3.negate = function (out, a) {
- out.x = -a.x;
- out.y = -a.y;
- out.z = -a.z;
- return out;
-};
-
-/**
- * Returns the inverse of the components of a vec3
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a vector to invert
- * @returns {vec3} out
- */
-vec3.inverse = function (out, a) {
- out.x = 1.0 / a.x;
- out.y = 1.0 / a.y;
- out.z = 1.0 / a.z;
- return out;
-};
-
-/**
- * Returns the inverse of the components of a vec3 safely
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a vector to invert
- * @returns {vec3} out
- */
-vec3.inverseSafe = function (out, a) {
- var x = a.x,
- y = a.y,
- z = a.z;
-
- if (Math.abs(x) < EPSILON) {
- out.x = 0;
- } else {
- out.x = 1.0 / x;
- }
-
- if (Math.abs(y) < EPSILON) {
- out.y = 0;
- } else {
- out.y = 1.0 / y;
- }
-
- if (Math.abs(z) < EPSILON) {
- out.z = 0;
- } else {
- out.z = 1.0 / z;
- }
-
- return out;
-};
-
-/**
- * Normalize a vec3
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a vector to normalize
- * @returns {vec3} out
- */
-vec3.normalize = function (out, a) {
- var x = a.x,
- y = a.y,
- z = a.z;
-
- var len = x * x + y * y + z * z;
- if (len > 0) {
- //TODO: evaluate use of glm_invsqrt here?
- len = 1 / Math.sqrt(len);
- out.x = x * len;
- out.y = y * len;
- out.z = z * len;
- }
- return out;
-};
-
-/**
- * Calculates the dot product of two vec3's
- *
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {Number} dot product of a and b
- */
-vec3.dot = function (a, b) {
- return a.x * b.x + a.y * b.y + a.z * b.z;
-};
-
-/**
- * Computes the cross product of two vec3's
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.cross = function (out, a, b) {
- var ax = a.x, ay = a.y, az = a.z,
- bx = b.x, by = b.y, bz = b.z;
-
- out.x = ay * bz - az * by;
- out.y = az * bx - ax * bz;
- out.z = ax * by - ay * bx;
- return out;
-};
-
-/**
- * Performs a linear interpolation between two vec3's
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {vec3} out
- */
-vec3.lerp = function (out, a, b, t) {
- var ax = a.x,
- ay = a.y,
- az = a.z;
- out.x = ax + t * (b.x - ax);
- out.y = ay + t * (b.y - ay);
- out.z = az + t * (b.z - az);
- return out;
-};
-
-/**
- * Performs a hermite interpolation with two control points
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @param {vec3} c the third operand
- * @param {vec3} d the fourth operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {vec3} out
- */
-vec3.hermite = function (out, a, b, c, d, t) {
- var factorTimes2 = t * t,
- factor1 = factorTimes2 * (2 * t - 3) + 1,
- factor2 = factorTimes2 * (t - 2) + t,
- factor3 = factorTimes2 * (t - 1),
- factor4 = factorTimes2 * (3 - 2 * t);
-
- out.x = a.x * factor1 + b.x * factor2 + c.x * factor3 + d.x * factor4;
- out.y = a.y * factor1 + b.y * factor2 + c.y * factor3 + d.y * factor4;
- out.z = a.z * factor1 + b.z * factor2 + c.z * factor3 + d.z * factor4;
-
- return out;
-};
-
-/**
- * Performs a bezier interpolation with two control points
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @param {vec3} c the third operand
- * @param {vec3} d the fourth operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {vec3} out
- */
-vec3.bezier = function (out, a, b, c, d, t) {
- var inverseFactor = 1 - t,
- inverseFactorTimesTwo = inverseFactor * inverseFactor,
- factorTimes2 = t * t,
- factor1 = inverseFactorTimesTwo * inverseFactor,
- factor2 = 3 * t * inverseFactorTimesTwo,
- factor3 = 3 * factorTimes2 * inverseFactor,
- factor4 = factorTimes2 * t;
-
- out.x = a.x * factor1 + b.x * factor2 + c.x * factor3 + d.x * factor4;
- out.y = a.y * factor1 + b.y * factor2 + c.y * factor3 + d.y * factor4;
- out.z = a.z * factor1 + b.z * factor2 + c.z * factor3 + d.z * factor4;
-
- return out;
-};
-
-/**
- * Generates a random vector with the given scale
- *
- * @param {vec3} out the receiving vector
- * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
- * @returns {vec3} out
- */
-vec3.random = function (out, scale) {
- scale = scale || 1.0;
-
- var r = random() * 2.0 * Math.PI;
- var z = (random() * 2.0) - 1.0;
- var zScale = Math.sqrt(1.0 - z * z) * scale;
-
- out.x = Math.cos(r) * zScale;
- out.y = Math.sin(r) * zScale;
- out.z = z * scale;
- return out;
-};
-
-/**
- * Transforms the vec3 with a mat4.
- * 4th vector component is implicitly '1'
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the vector to transform
- * @param {mat4} m matrix to transform with
- * @returns {vec3} out
- */
-vec3.transformMat4 = function (out, a, m) {
- var x = a.x, y = a.y, z = a.z,
- w = m.m03 * x + m.m07 * y + m.m11 * z + m.m15;
- w = w || 1.0;
- out.x = (m.m00 * x + m.m04 * y + m.m08 * z + m.m12) / w;
- out.y = (m.m01 * x + m.m05 * y + m.m09 * z + m.m13) / w;
- out.z = (m.m02 * x + m.m06 * y + m.m10 * z + m.m14) / w;
- return out;
-};
-
-/**
- * Transforms the vec3 with a mat3.
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the vector to transform
- * @param {mat4} m the 3x3 matrix to transform with
- * @returns {vec3} out
- */
-vec3.transformMat3 = function (out, a, m) {
- var x = a.x, y = a.y, z = a.z;
- out.x = x * m.m00 + y * m.m03 + z * m.m06;
- out.y = x * m.m01 + y * m.m04 + z * m.m07;
- out.z = x * m.m02 + y * m.m05 + z * m.m08;
- return out;
-};
-
-/**
- * Transforms the vec3 with a quat
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the vector to transform
- * @param {quat} q quaternion to transform with
- * @returns {vec3} out
- */
-vec3.transformQuat = function (out, a, q) {
- // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations
-
- var x = a.x, y = a.y, z = a.z;
- var qx = q.x, qy = q.y, qz = q.z, qw = q.w;
-
- // calculate quat * vec
- var ix = qw * x + qy * z - qz * y;
- var iy = qw * y + qz * x - qx * z;
- var iz = qw * z + qx * y - qy * x;
- var iw = -qx * x - qy * y - qz * z;
-
- // calculate result * inverse quat
- out.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
- out.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
- out.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
- return out;
-};
-
-/**
- * Rotate a 3D vector around the x-axis
- * @param {vec3} out The receiving vec3
- * @param {vec3} a The vec3 point to rotate
- * @param {vec3} b The origin of the rotation
- * @param {Number} c The angle of rotation
- * @returns {vec3} out
- */
-vec3.rotateX = function (out, a, b, c) {
- var p = [], r = [];
- // Translate point to the origin
- p.x = a.x - b.x;
- p.y = a.y - b.y;
- p.z = a.z - b.z;
-
- //perform rotation
- r.x = p.x;
- r.y = p.y * Math.cos(c) - p.z * Math.sin(c);
- r.z = p.y * Math.sin(c) + p.z * Math.cos(c);
-
- //translate to correct position
- out.x = r.x + b.x;
- out.y = r.y + b.y;
- out.z = r.z + b.z;
-
- return out;
-};
-
-/**
- * Rotate a 3D vector around the y-axis
- * @param {vec3} out The receiving vec3
- * @param {vec3} a The vec3 point to rotate
- * @param {vec3} b The origin of the rotation
- * @param {Number} c The angle of rotation
- * @returns {vec3} out
- */
-vec3.rotateY = function (out, a, b, c) {
- var p = [], r = [];
- //Translate point to the origin
- p.x = a.x - b.x;
- p.y = a.y - b.y;
- p.z = a.z - b.z;
-
- //perform rotation
- r.x = p.z * Math.sin(c) + p.x * Math.cos(c);
- r.y = p.y;
- r.z = p.z * Math.cos(c) - p.x * Math.sin(c);
-
- //translate to correct position
- out.x = r.x + b.x;
- out.y = r.y + b.y;
- out.z = r.z + b.z;
-
- return out;
-};
-
-/**
- * Rotate a 3D vector around the z-axis
- * @param {vec3} out The receiving vec3
- * @param {vec3} a The vec3 point to rotate
- * @param {vec3} b The origin of the rotation
- * @param {Number} c The angle of rotation
- * @returns {vec3} out
- */
-vec3.rotateZ = function (out, a, b, c) {
- var p = [], r = [];
- //Translate point to the origin
- p.x = a.x - b.x;
- p.y = a.y - b.y;
- p.z = a.z - b.z;
-
- //perform rotation
- r.x = p.x * Math.cos(c) - p.y * Math.sin(c);
- r.y = p.x * Math.sin(c) + p.y * Math.cos(c);
- r.z = p.z;
-
- //translate to correct position
- out.x = r.x + b.x;
- out.y = r.y + b.y;
- out.z = r.z + b.z;
-
- return out;
-};
-
-/**
- * Perform some operation over an array of vec3s.
- *
- * @param {Array} a the array of vectors to iterate over
- * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
- * @param {Number} offset Number of elements to skip at the beginning of the array
- * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
- * @param {Function} fn Function to call for each vector in the array
- * @param {Object} [arg] additional argument to pass to fn
- * @returns {Array} a
- * @function
- */
-vec3.forEach = (function () {
- var vec = vec3.create();
-
- return function (a, stride, offset, count, fn, arg) {
- var i, l;
- if (!stride) {
- stride = 3;
- }
-
- if (!offset) {
- offset = 0;
- }
-
- if (count) {
- l = Math.min((count * stride) + offset, a.length);
- } else {
- l = a.length;
- }
-
- for (i = offset; i < l; i += stride) {
- vec.x = a[i]; vec.y = a[i + 1]; vec.z = a[i + 2];
- fn(vec, vec, arg);
- a[i] = vec.x; a[i + 1] = vec.y; a[i + 2] = vec.z;
- }
-
- return a;
- };
-})();
-
-/**
- * Get the angle between two 3D vectors
- * @param {vec3} a The first operand
- * @param {vec3} b The second operand
- * @returns {Number} The angle in radians
- */
-vec3.angle = (function () {
- var tempA = vec3.create();
- var tempB = vec3.create();
-
- return function (a, b) {
- vec3.copy(tempA, a);
- vec3.copy(tempB, b);
-
- vec3.normalize(tempA, tempA);
- vec3.normalize(tempB, tempB);
-
- var cosine = vec3.dot(tempA, tempB);
-
- if (cosine > 1.0) {
- return 0;
- }
-
- if (cosine < -1.0) {
- return Math.PI;
- }
-
- return Math.acos(cosine);
- };
-})();
-
-/**
- * Returns a string representation of a vector
- *
- * @param {vec3} a vector to represent as a string
- * @returns {String} string representation of the vector
- */
-vec3.str = function (a) {
- return ("vec3(" + (a.x) + ", " + (a.y) + ", " + (a.z) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {vec3} v
- * @returns {array}
- */
-vec3.array = function (out, v) {
- out[0] = v.x;
- out[1] = v.y;
- out[2] = v.z;
-
- return out;
-};
-
-/**
- * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
- *
- * @param {vec3} a The first vector.
- * @param {vec3} b The second vector.
- * @returns {Boolean} True if the vectors are equal, false otherwise.
- */
-vec3.exactEquals = function (a, b) {
- return a.x === b.x && a.y === b.y && a.z === b.z;
-};
-
-/**
- * Returns whether or not the vectors have approximately the same elements in the same position.
- *
- * @param {vec3} a The first vector.
- * @param {vec3} b The second vector.
- * @returns {Boolean} True if the vectors are equal, false otherwise.
- */
-vec3.equals = function (a, b) {
- var a0 = a.x, a1 = a.y, a2 = a.z;
- var b0 = b.x, b1 = b.y, b2 = b.z;
- return (Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
- Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)));
-};
-
-var _tmp$2 = new Array(4);
-
-var _vec4 = function _vec4(x, y, z, w) {
- this.x = x;
- this.y = y;
- this.z = z;
- this.w = w;
-};
-
-_vec4.prototype.toJSON = function toJSON () {
- _tmp$2[0] = this.x;
- _tmp$2[1] = this.y;
- _tmp$2[2] = this.z;
- _tmp$2[3] = this.w;
-
- return _tmp$2;
-};
-
-/**
- * @class 4 Dimensional Vector
- * @name vec4
- */
-var vec4 = {};
-
-/**
- * Creates a new, empty vec4
- *
- * @returns {vec4} a new 4D vector
- */
-vec4.create = function () {
- return new _vec4(0, 0, 0, 0);
-};
-
-/**
- * Creates a new vec4 initialized with the given values
- *
- * @param {Number} x X component
- * @param {Number} y Y component
- * @param {Number} z Z component
- * @param {Number} w W component
- * @returns {vec4} a new 4D vector
- */
-vec4.new = function (x, y, z, w) {
- return new _vec4(x, y, z, w);
-};
-
-/**
- * Creates a new vec4 initialized with values from an existing vector
- *
- * @param {vec4} a vector to clone
- * @returns {vec4} a new 4D vector
- */
-vec4.clone = function (a) {
- return new _vec4(a.x, a.y, a.z, a.w);
-};
-
-/**
- * Copy the values from one vec4 to another
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the source vector
- * @returns {vec4} out
- */
-vec4.copy = function (out, a) {
- out.x = a.x;
- out.y = a.y;
- out.z = a.z;
- out.w = a.w;
- return out;
-};
-
-/**
- * Set the components of a vec4 to the given values
- *
- * @param {vec4} out the receiving vector
- * @param {Number} x X component
- * @param {Number} y Y component
- * @param {Number} z Z component
- * @param {Number} w W component
- * @returns {vec4} out
- */
-vec4.set = function (out, x, y, z, w) {
- out.x = x;
- out.y = y;
- out.z = z;
- out.w = w;
- return out;
-};
-
-/**
- * Adds two vec4's
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {vec4} out
- */
-vec4.add = function (out, a, b) {
- out.x = a.x + b.x;
- out.y = a.y + b.y;
- out.z = a.z + b.z;
- out.w = a.w + b.w;
- return out;
-};
-
-/**
- * Subtracts vector b from vector a
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {vec4} out
- */
-vec4.subtract = function (out, a, b) {
- out.x = a.x - b.x;
- out.y = a.y - b.y;
- out.z = a.z - b.z;
- out.w = a.w - b.w;
- return out;
-};
-
-/**
- * Alias for {@link vec4.subtract}
- * @function
- */
-vec4.sub = vec4.subtract;
-
-/**
- * Multiplies two vec4's
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {vec4} out
- */
-vec4.multiply = function (out, a, b) {
- out.x = a.x * b.x;
- out.y = a.y * b.y;
- out.z = a.z * b.z;
- out.w = a.w * b.w;
- return out;
-};
-
-/**
- * Alias for {@link vec4.multiply}
- * @function
- */
-vec4.mul = vec4.multiply;
-
-/**
- * Divides two vec4's
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {vec4} out
- */
-vec4.divide = function (out, a, b) {
- out.x = a.x / b.x;
- out.y = a.y / b.y;
- out.z = a.z / b.z;
- out.w = a.w / b.w;
- return out;
-};
-
-/**
- * Alias for {@link vec4.divide}
- * @function
- */
-vec4.div = vec4.divide;
-
-/**
- * Math.ceil the components of a vec4
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a vector to ceil
- * @returns {vec4} out
- */
-vec4.ceil = function (out, a) {
- out.x = Math.ceil(a.x);
- out.y = Math.ceil(a.y);
- out.z = Math.ceil(a.z);
- out.w = Math.ceil(a.w);
- return out;
-};
-
-/**
- * Math.floor the components of a vec4
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a vector to floor
- * @returns {vec4} out
- */
-vec4.floor = function (out, a) {
- out.x = Math.floor(a.x);
- out.y = Math.floor(a.y);
- out.z = Math.floor(a.z);
- out.w = Math.floor(a.w);
- return out;
-};
-
-/**
- * Returns the minimum of two vec4's
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {vec4} out
- */
-vec4.min = function (out, a, b) {
- out.x = Math.min(a.x, b.x);
- out.y = Math.min(a.y, b.y);
- out.z = Math.min(a.z, b.z);
- out.w = Math.min(a.w, b.w);
- return out;
-};
-
-/**
- * Returns the maximum of two vec4's
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {vec4} out
- */
-vec4.max = function (out, a, b) {
- out.x = Math.max(a.x, b.x);
- out.y = Math.max(a.y, b.y);
- out.z = Math.max(a.z, b.z);
- out.w = Math.max(a.w, b.w);
- return out;
-};
-
-/**
- * Math.round the components of a vec4
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a vector to round
- * @returns {vec4} out
- */
-vec4.round = function (out, a) {
- out.x = Math.round(a.x);
- out.y = Math.round(a.y);
- out.z = Math.round(a.z);
- out.w = Math.round(a.w);
- return out;
-};
-
-/**
- * Scales a vec4 by a scalar number
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the vector to scale
- * @param {Number} b amount to scale the vector by
- * @returns {vec4} out
- */
-vec4.scale = function (out, a, b) {
- out.x = a.x * b;
- out.y = a.y * b;
- out.z = a.z * b;
- out.w = a.w * b;
- return out;
-};
-
-/**
- * Adds two vec4's after scaling the second operand by a scalar value
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @param {Number} scale the amount to scale b by before adding
- * @returns {vec4} out
- */
-vec4.scaleAndAdd = function (out, a, b, scale) {
- out.x = a.x + (b.x * scale);
- out.y = a.y + (b.y * scale);
- out.z = a.z + (b.z * scale);
- out.w = a.w + (b.w * scale);
- return out;
-};
-
-/**
- * Calculates the euclidian distance between two vec4's
- *
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {Number} distance between a and b
- */
-vec4.distance = function (a, b) {
- var x = b.x - a.x,
- y = b.y - a.y,
- z = b.z - a.z,
- w = b.w - a.w;
- return Math.sqrt(x * x + y * y + z * z + w * w);
-};
-
-/**
- * Alias for {@link vec4.distance}
- * @function
- */
-vec4.dist = vec4.distance;
-
-/**
- * Calculates the squared euclidian distance between two vec4's
- *
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {Number} squared distance between a and b
- */
-vec4.squaredDistance = function (a, b) {
- var x = b.x - a.x,
- y = b.y - a.y,
- z = b.z - a.z,
- w = b.w - a.w;
- return x * x + y * y + z * z + w * w;
-};
-
-/**
- * Alias for {@link vec4.squaredDistance}
- * @function
- */
-vec4.sqrDist = vec4.squaredDistance;
-
-/**
- * Calculates the length of a vec4
- *
- * @param {vec4} a vector to calculate length of
- * @returns {Number} length of a
- */
-vec4.length = function (a) {
- var x = a.x,
- y = a.y,
- z = a.z,
- w = a.w;
- return Math.sqrt(x * x + y * y + z * z + w * w);
-};
-
-/**
- * Alias for {@link vec4.length}
- * @function
- */
-vec4.len = vec4.length;
-
-/**
- * Calculates the squared length of a vec4
- *
- * @param {vec4} a vector to calculate squared length of
- * @returns {Number} squared length of a
- */
-vec4.squaredLength = function (a) {
- var x = a.x,
- y = a.y,
- z = a.z,
- w = a.w;
- return x * x + y * y + z * z + w * w;
-};
-
-/**
- * Alias for {@link vec4.squaredLength}
- * @function
- */
-vec4.sqrLen = vec4.squaredLength;
-
-/**
- * Negates the components of a vec4
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a vector to negate
- * @returns {vec4} out
- */
-vec4.negate = function (out, a) {
- out.x = -a.x;
- out.y = -a.y;
- out.z = -a.z;
- out.w = -a.w;
- return out;
-};
-
-/**
- * Returns the inverse of the components of a vec4
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a vector to invert
- * @returns {vec4} out
- */
-vec4.inverse = function (out, a) {
- out.x = 1.0 / a.x;
- out.y = 1.0 / a.y;
- out.z = 1.0 / a.z;
- out.w = 1.0 / a.w;
- return out;
-};
-
-/**
- * Returns the inverse of the components of a vec4 safely
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a vector to invert
- * @returns {vec4} out
- */
-vec4.inverseSafe = function (out, a) {
- var x = a.x,
- y = a.y,
- z = a.z,
- w = a.w;
-
- if (Math.abs(x) < EPSILON) {
- out.x = 0;
- } else {
- out.x = 1.0 / x;
- }
-
- if (Math.abs(y) < EPSILON) {
- out.y = 0;
- } else {
- out.y = 1.0 / y;
- }
-
- if (Math.abs(z) < EPSILON) {
- out.z = 0;
- } else {
- out.z = 1.0 / z;
- }
-
- if (Math.abs(w) < EPSILON) {
- out.w = 0;
- } else {
- out.w = 1.0 / w;
- }
-
- return out;
-};
-
-/**
- * Normalize a vec4
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a vector to normalize
- * @returns {vec4} out
- */
-vec4.normalize = function (out, a) {
- var x = a.x,
- y = a.y,
- z = a.z,
- w = a.w;
- var len = x * x + y * y + z * z + w * w;
- if (len > 0) {
- len = 1 / Math.sqrt(len);
- out.x = x * len;
- out.y = y * len;
- out.z = z * len;
- out.w = w * len;
- }
- return out;
-};
-
-/**
- * Calculates the dot product of two vec4's
- *
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {Number} dot product of a and b
- */
-vec4.dot = function (a, b) {
- return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
-};
-
-/**
- * Performs a linear interpolation between two vec4's
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {vec4} out
- */
-vec4.lerp = function (out, a, b, t) {
- var ax = a.x,
- ay = a.y,
- az = a.z,
- aw = a.w;
- out.x = ax + t * (b.x - ax);
- out.y = ay + t * (b.y - ay);
- out.z = az + t * (b.z - az);
- out.w = aw + t * (b.w - aw);
- return out;
-};
-
-/**
- * Generates a random vector with the given scale
- *
- * @param {vec4} out the receiving vector
- * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
- * @returns {vec4} out
- */
-vec4.random = function (out, scale) {
- scale = scale || 1.0;
-
- //TODO: This is a pretty awful way of doing this. Find something better.
- out.x = random();
- out.y = random();
- out.z = random();
- out.w = random();
- vec4.normalize(out, out);
- vec4.scale(out, out, scale);
- return out;
-};
-
-/**
- * Transforms the vec4 with a mat4.
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the vector to transform
- * @param {mat4} m matrix to transform with
- * @returns {vec4} out
- */
-vec4.transformMat4 = function (out, a, m) {
- var x = a.x, y = a.y, z = a.z, w = a.w;
- out.x = m.m00 * x + m.m04 * y + m.m08 * z + m.m12 * w;
- out.y = m.m01 * x + m.m05 * y + m.m09 * z + m.m13 * w;
- out.z = m.m02 * x + m.m06 * y + m.m10 * z + m.m14 * w;
- out.w = m.m03 * x + m.m07 * y + m.m11 * z + m.m15 * w;
- return out;
-};
-
-/**
- * Transforms the vec4 with a quat
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the vector to transform
- * @param {quat} q quaternion to transform with
- * @returns {vec4} out
- */
-vec4.transformQuat = function (out, a, q) {
- var x = a.x, y = a.y, z = a.z;
- var qx = q.x, qy = q.y, qz = q.z, qw = q.w;
-
- // calculate quat * vec
- var ix = qw * x + qy * z - qz * y;
- var iy = qw * y + qz * x - qx * z;
- var iz = qw * z + qx * y - qy * x;
- var iw = -qx * x - qy * y - qz * z;
-
- // calculate result * inverse quat
- out.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
- out.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
- out.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
- out.w = a.w;
- return out;
-};
-
-/**
- * Perform some operation over an array of vec4s.
- *
- * @param {Array} a the array of vectors to iterate over
- * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
- * @param {Number} offset Number of elements to skip at the beginning of the array
- * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array
- * @param {Function} fn Function to call for each vector in the array
- * @param {Object} [arg] additional argument to pass to fn
- * @returns {Array} a
- * @function
- */
-vec4.forEach = (function () {
- var vec = vec4.create();
-
- return function (a, stride, offset, count, fn, arg) {
- var i, l;
- if (!stride) {
- stride = 4;
- }
-
- if (!offset) {
- offset = 0;
- }
-
- if (count) {
- l = Math.min((count * stride) + offset, a.length);
- } else {
- l = a.length;
- }
-
- for (i = offset; i < l; i += stride) {
- vec.x = a[i]; vec.y = a[i + 1]; vec.z = a[i + 2]; vec.w = a[i + 3];
- fn(vec, vec, arg);
- a[i] = vec.x; a[i + 1] = vec.y; a[i + 2] = vec.z; a[i + 3] = vec.w;
- }
-
- return a;
- };
-})();
-
-/**
- * Returns a string representation of a vector
- *
- * @param {vec4} a vector to represent as a string
- * @returns {String} string representation of the vector
- */
-vec4.str = function (a) {
- return ("vec4(" + (a.x) + ", " + (a.y) + ", " + (a.z) + ", " + (a.w) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {vec4} v
- * @returns {array}
- */
-vec4.array = function (out, v) {
- out[0] = v.x;
- out[1] = v.y;
- out[2] = v.z;
- out[3] = v.w;
-
- return out;
-};
-
-/**
- * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
- *
- * @param {vec4} a The first vector.
- * @param {vec4} b The second vector.
- * @returns {Boolean} True if the vectors are equal, false otherwise.
- */
-vec4.exactEquals = function (a, b) {
- return a.x === b.x && a.y === b.y && a.z === b.z && a.w === b.w;
-};
-
-/**
- * Returns whether or not the vectors have approximately the same elements in the same position.
- *
- * @param {vec4} a The first vector.
- * @param {vec4} b The second vector.
- * @returns {Boolean} True if the vectors are equal, false otherwise.
- */
-vec4.equals = function (a, b) {
- var a0 = a.x, a1 = a.y, a2 = a.z, a3 = a.w;
- var b0 = b.x, b1 = b.y, b2 = b.z, b3 = b.w;
- return (Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
- Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
- Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)));
-};
-
-var _tmp$3 = new Array(9);
-
-var _mat3 = function _mat3(m00, m01, m02, m03, m04, m05, m06, m07, m08) {
- this.m00 = m00;
- this.m01 = m01;
- this.m02 = m02;
- this.m03 = m03;
- this.m04 = m04;
- this.m05 = m05;
- this.m06 = m06;
- this.m07 = m07;
- this.m08 = m08;
-};
-
-_mat3.prototype.toJSON = function toJSON () {
- _tmp$3[0] = this.m00;
- _tmp$3[1] = this.m01;
- _tmp$3[2] = this.m02;
- _tmp$3[3] = this.m03;
- _tmp$3[4] = this.m04;
- _tmp$3[5] = this.m05;
- _tmp$3[6] = this.m06;
- _tmp$3[7] = this.m07;
- _tmp$3[8] = this.m08;
-
- return _tmp$3;
-};
-
-/**
- * @class 3x3 Matrix
- * @name mat3
- *
- * NOTE: we use column-major matrix for all matrix calculation.
- *
- * This may lead to some confusion when referencing OpenGL documentation,
- * however, which represents out all matricies in column-major format.
- * This means that while in code a matrix may be typed out as:
- *
- * [1, 0, 0, 0,
- * 0, 1, 0, 0,
- * 0, 0, 1, 0,
- * x, y, z, 0]
- *
- * The same matrix in the [OpenGL documentation](https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTranslate.xml)
- * is written as:
- *
- * 1 0 0 x
- * 0 1 0 y
- * 0 0 1 z
- * 0 0 0 0
- *
- * Please rest assured, however, that they are the same thing!
- * This is not unique to glMatrix, either, as OpenGL developers have long been confused by the
- * apparent lack of consistency between the memory layout and the documentation.
- */
-var mat3 = {};
-
-/**
- * Creates a new identity mat3
- *
- * @returns {mat3} a new 3x3 matrix
- */
-mat3.create = function () {
- return new _mat3(
- 1, 0, 0,
- 0, 1, 0,
- 0, 0, 1
- );
-};
-
-/**
- * Create a new mat3 with the given values
- *
- * @param {Number} m00 Component in column 0, row 0 position (index 0)
- * @param {Number} m01 Component in column 0, row 1 position (index 1)
- * @param {Number} m02 Component in column 0, row 2 position (index 2)
- * @param {Number} m10 Component in column 1, row 0 position (index 3)
- * @param {Number} m11 Component in column 1, row 1 position (index 4)
- * @param {Number} m12 Component in column 1, row 2 position (index 5)
- * @param {Number} m20 Component in column 2, row 0 position (index 6)
- * @param {Number} m21 Component in column 2, row 1 position (index 7)
- * @param {Number} m22 Component in column 2, row 2 position (index 8)
- * @returns {mat3} A new mat3
- */
-mat3.new = function (m00, m01, m02, m10, m11, m12, m20, m21, m22) {
- return new _mat3(
- m00, m01, m02,
- m10, m11, m12,
- m20, m21, m22
- );
-};
-
-/**
- * Creates a new mat3 initialized with values from an existing matrix
- *
- * @param {mat3} a matrix to clone
- * @returns {mat3} a new 3x3 matrix
- */
-mat3.clone = function (a) {
- return new _mat3(
- a.m00, a.m01, a.m02,
- a.m03, a.m04, a.m05,
- a.m06, a.m07, a.m08
- );
-};
-
-/**
- * Copy the values from one mat3 to another
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the source matrix
- * @returns {mat3} out
- */
-mat3.copy = function (out, a) {
- out.m00 = a.m00;
- out.m01 = a.m01;
- out.m02 = a.m02;
- out.m03 = a.m03;
- out.m04 = a.m04;
- out.m05 = a.m05;
- out.m06 = a.m06;
- out.m07 = a.m07;
- out.m08 = a.m08;
- return out;
-};
-
-/**
- * Set the components of a mat3 to the given values
- *
- * @param {mat3} out the receiving matrix
- * @param {Number} m00 Component in column 0, row 0 position (index 0)
- * @param {Number} m01 Component in column 0, row 1 position (index 1)
- * @param {Number} m02 Component in column 0, row 2 position (index 2)
- * @param {Number} m10 Component in column 1, row 0 position (index 3)
- * @param {Number} m11 Component in column 1, row 1 position (index 4)
- * @param {Number} m12 Component in column 1, row 2 position (index 5)
- * @param {Number} m20 Component in column 2, row 0 position (index 6)
- * @param {Number} m21 Component in column 2, row 1 position (index 7)
- * @param {Number} m22 Component in column 2, row 2 position (index 8)
- * @returns {mat3} out
- */
-mat3.set = function (out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {
- out.m00 = m00;
- out.m01 = m01;
- out.m02 = m02;
- out.m03 = m10;
- out.m04 = m11;
- out.m05 = m12;
- out.m06 = m20;
- out.m07 = m21;
- out.m08 = m22;
- return out;
-};
-
-/**
- * Set a mat3 to the identity matrix
- *
- * @param {mat3} out the receiving matrix
- * @returns {mat3} out
- */
-mat3.identity = function (out) {
- out.m00 = 1;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 1;
- out.m05 = 0;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 1;
- return out;
-};
-
-/**
- * Transpose the values of a mat3
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the source matrix
- * @returns {mat3} out
- */
-mat3.transpose = function (out, a) {
- // If we are transposing ourselves we can skip a few steps but have to cache some values
- if (out === a) {
- var a01 = a.m01, a02 = a.m02, a12 = a.m05;
- out.m01 = a.m03;
- out.m02 = a.m06;
- out.m03 = a01;
- out.m05 = a.m07;
- out.m06 = a02;
- out.m07 = a12;
- } else {
- out.m00 = a.m00;
- out.m01 = a.m03;
- out.m02 = a.m06;
- out.m03 = a.m01;
- out.m04 = a.m04;
- out.m05 = a.m07;
- out.m06 = a.m02;
- out.m07 = a.m05;
- out.m08 = a.m08;
- }
-
- return out;
-};
-
-/**
- * Inverts a mat3
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the source matrix
- * @returns {mat3} out
- */
-mat3.invert = function (out, a) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02,
- a10 = a.m03, a11 = a.m04, a12 = a.m05,
- a20 = a.m06, a21 = a.m07, a22 = a.m08;
-
- var b01 = a22 * a11 - a12 * a21;
- var b11 = -a22 * a10 + a12 * a20;
- var b21 = a21 * a10 - a11 * a20;
-
- // Calculate the determinant
- var det = a00 * b01 + a01 * b11 + a02 * b21;
-
- if (!det) {
- return null;
- }
- det = 1.0 / det;
-
- out.m00 = b01 * det;
- out.m01 = (-a22 * a01 + a02 * a21) * det;
- out.m02 = (a12 * a01 - a02 * a11) * det;
- out.m03 = b11 * det;
- out.m04 = (a22 * a00 - a02 * a20) * det;
- out.m05 = (-a12 * a00 + a02 * a10) * det;
- out.m06 = b21 * det;
- out.m07 = (-a21 * a00 + a01 * a20) * det;
- out.m08 = (a11 * a00 - a01 * a10) * det;
- return out;
-};
-
-/**
- * Calculates the adjugate of a mat3
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the source matrix
- * @returns {mat3} out
- */
-mat3.adjoint = function (out, a) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02,
- a10 = a.m03, a11 = a.m04, a12 = a.m05,
- a20 = a.m06, a21 = a.m07, a22 = a.m08;
-
- out.m00 = (a11 * a22 - a12 * a21);
- out.m01 = (a02 * a21 - a01 * a22);
- out.m02 = (a01 * a12 - a02 * a11);
- out.m03 = (a12 * a20 - a10 * a22);
- out.m04 = (a00 * a22 - a02 * a20);
- out.m05 = (a02 * a10 - a00 * a12);
- out.m06 = (a10 * a21 - a11 * a20);
- out.m07 = (a01 * a20 - a00 * a21);
- out.m08 = (a00 * a11 - a01 * a10);
- return out;
-};
-
-/**
- * Calculates the determinant of a mat3
- *
- * @param {mat3} a the source matrix
- * @returns {Number} determinant of a
- */
-mat3.determinant = function (a) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02,
- a10 = a.m03, a11 = a.m04, a12 = a.m05,
- a20 = a.m06, a21 = a.m07, a22 = a.m08;
-
- return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
-};
-
-/**
- * Multiplies two mat3's
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the first operand
- * @param {mat3} b the second operand
- * @returns {mat3} out
- */
-mat3.multiply = function (out, a, b) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02,
- a10 = a.m03, a11 = a.m04, a12 = a.m05,
- a20 = a.m06, a21 = a.m07, a22 = a.m08;
-
- var b00 = b.m00, b01 = b.m01, b02 = b.m02;
- var b10 = b.m03, b11 = b.m04, b12 = b.m05;
- var b20 = b.m06, b21 = b.m07, b22 = b.m08;
-
- out.m00 = b00 * a00 + b01 * a10 + b02 * a20;
- out.m01 = b00 * a01 + b01 * a11 + b02 * a21;
- out.m02 = b00 * a02 + b01 * a12 + b02 * a22;
-
- out.m03 = b10 * a00 + b11 * a10 + b12 * a20;
- out.m04 = b10 * a01 + b11 * a11 + b12 * a21;
- out.m05 = b10 * a02 + b11 * a12 + b12 * a22;
-
- out.m06 = b20 * a00 + b21 * a10 + b22 * a20;
- out.m07 = b20 * a01 + b21 * a11 + b22 * a21;
- out.m08 = b20 * a02 + b21 * a12 + b22 * a22;
- return out;
-};
-
-/**
- * Alias for {@link mat3.multiply}
- * @function
- */
-mat3.mul = mat3.multiply;
-
-/**
- * Translate a mat3 by the given vector
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the matrix to translate
- * @param {vec2} v vector to translate by
- * @returns {mat3} out
- */
-mat3.translate = function (out, a, v) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02,
- a10 = a.m03, a11 = a.m04, a12 = a.m05,
- a20 = a.m06, a21 = a.m07, a22 = a.m08;
- var x = v.x, y = v.y;
-
- out.m00 = a00;
- out.m01 = a01;
- out.m02 = a02;
-
- out.m03 = a10;
- out.m04 = a11;
- out.m05 = a12;
-
- out.m06 = x * a00 + y * a10 + a20;
- out.m07 = x * a01 + y * a11 + a21;
- out.m08 = x * a02 + y * a12 + a22;
- return out;
-};
-
-/**
- * Rotates a mat3 by the given angle
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat3} out
- */
-mat3.rotate = function (out, a, rad) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02,
- a10 = a.m03, a11 = a.m04, a12 = a.m05,
- a20 = a.m06, a21 = a.m07, a22 = a.m08;
-
- var s = Math.sin(rad);
- var c = Math.cos(rad);
-
- out.m00 = c * a00 + s * a10;
- out.m01 = c * a01 + s * a11;
- out.m02 = c * a02 + s * a12;
-
- out.m03 = c * a10 - s * a00;
- out.m04 = c * a11 - s * a01;
- out.m05 = c * a12 - s * a02;
-
- out.m06 = a20;
- out.m07 = a21;
- out.m08 = a22;
- return out;
-};
-
-/**
- * Scales the mat3 by the dimensions in the given vec2
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the matrix to rotate
- * @param {vec2} v the vec2 to scale the matrix by
- * @returns {mat3} out
- **/
-mat3.scale = function (out, a, v) {
- var x = v.x, y = v.y;
-
- out.m00 = x * a.m00;
- out.m01 = x * a.m01;
- out.m02 = x * a.m02;
-
- out.m03 = y * a.m03;
- out.m04 = y * a.m04;
- out.m05 = y * a.m05;
-
- out.m06 = a.m06;
- out.m07 = a.m07;
- out.m08 = a.m08;
- return out;
-};
-
-/**
- * Copies the upper-left 3x3 values into the given mat3.
- *
- * @param {mat3} out the receiving 3x3 matrix
- * @param {mat4} a the source 4x4 matrix
- * @returns {mat3} out
- */
-mat3.fromMat4 = function (out, a) {
- out.m00 = a.m00;
- out.m01 = a.m01;
- out.m02 = a.m02;
- out.m03 = a.m04;
- out.m04 = a.m05;
- out.m05 = a.m06;
- out.m06 = a.m08;
- out.m07 = a.m09;
- out.m08 = a.m10;
- return out;
-};
-
-/**
- * Creates a matrix from a vector translation
- * This is equivalent to (but much faster than):
- *
- * mat3.identity(dest);
- * mat3.translate(dest, dest, vec);
- *
- * @param {mat3} out mat3 receiving operation result
- * @param {vec2} v Translation vector
- * @returns {mat3} out
- */
-mat3.fromTranslation = function (out, v) {
- out.m00 = 1;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 1;
- out.m05 = 0;
- out.m06 = v.x;
- out.m07 = v.y;
- out.m08 = 1;
- return out;
-};
-
-/**
- * Creates a matrix from a given angle
- * This is equivalent to (but much faster than):
- *
- * mat3.identity(dest);
- * mat3.rotate(dest, dest, rad);
- *
- * @param {mat3} out mat3 receiving operation result
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat3} out
- */
-mat3.fromRotation = function (out, rad) {
- var s = Math.sin(rad), c = Math.cos(rad);
-
- out.m00 = c;
- out.m01 = s;
- out.m02 = 0;
-
- out.m03 = -s;
- out.m04 = c;
- out.m05 = 0;
-
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 1;
- return out;
-};
-
-/**
- * Creates a matrix from a vector scaling
- * This is equivalent to (but much faster than):
- *
- * mat3.identity(dest);
- * mat3.scale(dest, dest, vec);
- *
- * @param {mat3} out mat3 receiving operation result
- * @param {vec2} v Scaling vector
- * @returns {mat3} out
- */
-mat3.fromScaling = function (out, v) {
- out.m00 = v.x;
- out.m01 = 0;
- out.m02 = 0;
-
- out.m03 = 0;
- out.m04 = v.y;
- out.m05 = 0;
-
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 1;
- return out;
-};
-
-/**
- * Copies the values from a mat2d into a mat3
- *
- * @param {mat3} out the receiving matrix
- * @param {mat2d} a the matrix to copy
- * @returns {mat3} out
- **/
-mat3.fromMat2d = function (out, a) {
- out.m00 = a.m00;
- out.m01 = a.m01;
- out.m02 = 0;
-
- out.m03 = a.m02;
- out.m04 = a.m03;
- out.m05 = 0;
-
- out.m06 = a.m04;
- out.m07 = a.m05;
- out.m08 = 1;
- return out;
-};
-
-/**
-* Calculates a 3x3 matrix from the given quaternion
-*
-* @param {mat3} out mat3 receiving operation result
-* @param {quat} q Quaternion to create matrix from
-*
-* @returns {mat3} out
-*/
-mat3.fromQuat = function (out, q) {
- var x = q.x, y = q.y, z = q.z, w = q.w;
- var x2 = x + x;
- var y2 = y + y;
- var z2 = z + z;
-
- var xx = x * x2;
- var yx = y * x2;
- var yy = y * y2;
- var zx = z * x2;
- var zy = z * y2;
- var zz = z * z2;
- var wx = w * x2;
- var wy = w * y2;
- var wz = w * z2;
-
- out.m00 = 1 - yy - zz;
- out.m03 = yx - wz;
- out.m06 = zx + wy;
-
- out.m01 = yx + wz;
- out.m04 = 1 - xx - zz;
- out.m07 = zy - wx;
-
- out.m02 = zx - wy;
- out.m05 = zy + wx;
- out.m08 = 1 - xx - yy;
-
- return out;
-};
-
-/**
-* Calculates a 3x3 matrix from view direction and up direction
-*
-* @param {mat3} out mat3 receiving operation result
-* @param {vec3} view view direction (must be normalized)
-* @param {vec3} [up] up direction, default is (0,1,0) (must be normalized)
-*
-* @returns {mat3} out
-*/
-mat3.fromViewUp = (function () {
- var default_up = vec3.new(0, 1, 0);
- var x = vec3.create();
- var y = vec3.create();
-
- return function (out, view, up) {
- if (vec3.sqrLen(view) < EPSILON * EPSILON) {
- mat3.identity(out);
- return out;
- }
-
- up = up || default_up;
- vec3.cross(x, up, view);
-
- if (vec3.sqrLen(x) < EPSILON * EPSILON) {
- mat3.identity(out);
- return out;
- }
-
- vec3.cross(y, view, x);
- mat3.set(out,
- x.x, x.y, x.z,
- y.x, y.y, y.z,
- view.x, view.y, view.z
- );
-
- return out;
- };
-})();
-
-/**
-* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
-*
-* @param {mat3} out mat3 receiving operation result
-* @param {mat4} a Mat4 to derive the normal matrix from
-*
-* @returns {mat3} out
-*/
-mat3.normalFromMat4 = function (out, a) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02, a03 = a.m03,
- a10 = a.m04, a11 = a.m05, a12 = a.m06, a13 = a.m07,
- a20 = a.m08, a21 = a.m09, a22 = a.m10, a23 = a.m11,
- a30 = a.m12, a31 = a.m13, a32 = a.m14, a33 = a.m15;
-
- var b00 = a00 * a11 - a01 * a10;
- var b01 = a00 * a12 - a02 * a10;
- var b02 = a00 * a13 - a03 * a10;
- var b03 = a01 * a12 - a02 * a11;
- var b04 = a01 * a13 - a03 * a11;
- var b05 = a02 * a13 - a03 * a12;
- var b06 = a20 * a31 - a21 * a30;
- var b07 = a20 * a32 - a22 * a30;
- var b08 = a20 * a33 - a23 * a30;
- var b09 = a21 * a32 - a22 * a31;
- var b10 = a21 * a33 - a23 * a31;
- var b11 = a22 * a33 - a23 * a32;
-
- // Calculate the determinant
- var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
-
- if (!det) {
- return null;
- }
- det = 1.0 / det;
-
- out.m00 = (a11 * b11 - a12 * b10 + a13 * b09) * det;
- out.m01 = (a12 * b08 - a10 * b11 - a13 * b07) * det;
- out.m02 = (a10 * b10 - a11 * b08 + a13 * b06) * det;
-
- out.m03 = (a02 * b10 - a01 * b11 - a03 * b09) * det;
- out.m04 = (a00 * b11 - a02 * b08 + a03 * b07) * det;
- out.m05 = (a01 * b08 - a00 * b10 - a03 * b06) * det;
-
- out.m06 = (a31 * b05 - a32 * b04 + a33 * b03) * det;
- out.m07 = (a32 * b02 - a30 * b05 - a33 * b01) * det;
- out.m08 = (a30 * b04 - a31 * b02 + a33 * b00) * det;
-
- return out;
-};
-
-/**
- * Returns a string representation of a mat3
- *
- * @param {mat3} a matrix to represent as a string
- * @returns {String} string representation of the matrix
- */
-mat3.str = function (a) {
- return ("mat3(" + (a.m00) + ", " + (a.m01) + ", " + (a.m02) + ", " + (a.m03) + ", " + (a.m04) + ", " + (a.m05) + ", " + (a.m06) + ", " + (a.m07) + ", " + (a.m08) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {mat3} m
- * @returns {array}
- */
-mat3.array = function (out, m) {
- out[0] = m.m00;
- out[1] = m.m01;
- out[2] = m.m02;
- out[3] = m.m03;
- out[4] = m.m04;
- out[5] = m.m05;
- out[6] = m.m06;
- out[7] = m.m07;
- out[8] = m.m08;
-
- return out;
-};
-
-/**
- * Returns Frobenius norm of a mat3
- *
- * @param {mat3} a the matrix to calculate Frobenius norm of
- * @returns {Number} Frobenius norm
- */
-mat3.frob = function (a) {
- return (Math.sqrt(Math.pow(a.m00, 2) + Math.pow(a.m01, 2) + Math.pow(a.m02, 2) + Math.pow(a.m03, 2) + Math.pow(a.m04, 2) + Math.pow(a.m05, 2) + Math.pow(a.m06, 2) + Math.pow(a.m07, 2) + Math.pow(a.m08, 2)));
-};
-
-/**
- * Adds two mat3's
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the first operand
- * @param {mat3} b the second operand
- * @returns {mat3} out
- */
-mat3.add = function (out, a, b) {
- out.m00 = a.m00 + b.m00;
- out.m01 = a.m01 + b.m01;
- out.m02 = a.m02 + b.m02;
- out.m03 = a.m03 + b.m03;
- out.m04 = a.m04 + b.m04;
- out.m05 = a.m05 + b.m05;
- out.m06 = a.m06 + b.m06;
- out.m07 = a.m07 + b.m07;
- out.m08 = a.m08 + b.m08;
- return out;
-};
-
-/**
- * Subtracts matrix b from matrix a
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the first operand
- * @param {mat3} b the second operand
- * @returns {mat3} out
- */
-mat3.subtract = function (out, a, b) {
- out.m00 = a.m00 - b.m00;
- out.m01 = a.m01 - b.m01;
- out.m02 = a.m02 - b.m02;
- out.m03 = a.m03 - b.m03;
- out.m04 = a.m04 - b.m04;
- out.m05 = a.m05 - b.m05;
- out.m06 = a.m06 - b.m06;
- out.m07 = a.m07 - b.m07;
- out.m08 = a.m08 - b.m08;
- return out;
-};
-
-/**
- * Alias for {@link mat3.subtract}
- * @function
- */
-mat3.sub = mat3.subtract;
-
-/**
- * Multiply each element of the matrix by a scalar.
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the matrix to scale
- * @param {Number} b amount to scale the matrix's elements by
- * @returns {mat3} out
- */
-mat3.multiplyScalar = function (out, a, b) {
- out.m00 = a.m00 * b;
- out.m01 = a.m01 * b;
- out.m02 = a.m02 * b;
- out.m03 = a.m03 * b;
- out.m04 = a.m04 * b;
- out.m05 = a.m05 * b;
- out.m06 = a.m06 * b;
- out.m07 = a.m07 * b;
- out.m08 = a.m08 * b;
- return out;
-};
-
-/**
- * Adds two mat3's after multiplying each element of the second operand by a scalar value.
- *
- * @param {mat3} out the receiving vector
- * @param {mat3} a the first operand
- * @param {mat3} b the second operand
- * @param {Number} scale the amount to scale b's elements by before adding
- * @returns {mat3} out
- */
-mat3.multiplyScalarAndAdd = function (out, a, b, scale) {
- out.m00 = a.m00 + (b.m00 * scale);
- out.m01 = a.m01 + (b.m01 * scale);
- out.m02 = a.m02 + (b.m02 * scale);
- out.m03 = a.m03 + (b.m03 * scale);
- out.m04 = a.m04 + (b.m04 * scale);
- out.m05 = a.m05 + (b.m05 * scale);
- out.m06 = a.m06 + (b.m06 * scale);
- out.m07 = a.m07 + (b.m07 * scale);
- out.m08 = a.m08 + (b.m08 * scale);
- return out;
-};
-
-/**
- * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
- *
- * @param {mat3} a The first matrix.
- * @param {mat3} b The second matrix.
- * @returns {Boolean} True if the matrices are equal, false otherwise.
- */
-mat3.exactEquals = function (a, b) {
- return a.m00 === b.m00 && a.m01 === b.m01 && a.m02 === b.m02 &&
- a.m03 === b.m03 && a.m04 === b.m04 && a.m05 === b.m05 &&
- a.m06 === b.m06 && a.m07 === b.m07 && a.m08 === b.m08;
-};
-
-/**
- * Returns whether or not the matrices have approximately the same elements in the same position.
- *
- * @param {mat3} a The first matrix.
- * @param {mat3} b The second matrix.
- * @returns {Boolean} True if the matrices are equal, false otherwise.
- */
-mat3.equals = function (a, b) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03, a4 = a.m04, a5 = a.m05, a6 = a.m06, a7 = a.m07, a8 = a.m08;
- var b0 = b.m00, b1 = b.m01, b2 = b.m02, b3 = b.m03, b4 = b.m04, b5 = b.m05, b6 = b.m06, b7 = b.m07, b8 = b.m08;
- return (
- Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
- Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
- Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&
- Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&
- Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&
- Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&
- Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) &&
- Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8))
- );
-};
-
-var _tmp$4 = new Array(4);
-
-var _quat = function _quat(x, y, z, w) {
- this.x = x;
- this.y = y;
- this.z = z;
- this.w = w;
-};
-
-_quat.prototype.toJSON = function toJSON () {
- _tmp$4[0] = this.x;
- _tmp$4[1] = this.y;
- _tmp$4[2] = this.z;
- _tmp$4[3] = this.w;
-
- return _tmp$4;
-};
-
-/**
- * @class Quaternion
- * @name quat
- */
-var quat = {};
-
-/**
- * Creates a new identity quat
- *
- * @returns {quat} a new quaternion
- */
-quat.create = function () {
- return new _quat(0, 0, 0, 1);
-};
-
-/**
- * Creates a new quat initialized with the given values
- *
- * @param {Number} x X component
- * @param {Number} y Y component
- * @param {Number} z Z component
- * @param {Number} w W component
- * @returns {quat} a new quaternion
- * @function
- */
-quat.new = function (x, y, z, w) {
- return new _quat(x, y, z, w);
-};
-
-/**
- * Creates a new quat initialized with values from an existing quaternion
- *
- * @param {quat} a quaternion to clone
- * @returns {quat} a new quaternion
- * @function
- */
-quat.clone = function (a) {
- return new _quat(a.x, a.y, a.z, a.w);
-};
-
-/**
- * Copy the values from one quat to another
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a the source quaternion
- * @returns {quat} out
- * @function
- */
-quat.copy = vec4.copy;
-
-/**
- * Set the components of a quat to the given values
- *
- * @param {quat} out the receiving quaternion
- * @param {Number} x X component
- * @param {Number} y Y component
- * @param {Number} z Z component
- * @param {Number} w W component
- * @returns {quat} out
- * @function
- */
-quat.set = vec4.set;
-
-/**
- * Set a quat to the identity quaternion
- *
- * @param {quat} out the receiving quaternion
- * @returns {quat} out
- */
-quat.identity = function (out) {
- out.x = 0;
- out.y = 0;
- out.z = 0;
- out.w = 1;
- return out;
-};
-
-/**
- * Sets a quaternion to represent the shortest rotation from one
- * vector to another.
- *
- * Both vectors are assumed to be unit length.
- *
- * @param {quat} out the receiving quaternion.
- * @param {vec3} a the initial vector
- * @param {vec3} b the destination vector
- * @returns {quat} out
- */
-quat.rotationTo = (function () {
- var tmpvec3 = vec3.create();
- var xUnitVec3 = vec3.new(1, 0, 0);
- var yUnitVec3 = vec3.new(0, 1, 0);
-
- return function (out, a, b) {
- var dot = vec3.dot(a, b);
- if (dot < -0.999999) {
- vec3.cross(tmpvec3, xUnitVec3, a);
- if (vec3.length(tmpvec3) < 0.000001) {
- vec3.cross(tmpvec3, yUnitVec3, a);
- }
- vec3.normalize(tmpvec3, tmpvec3);
- quat.fromAxisAngle(out, tmpvec3, Math.PI);
- return out;
- } else if (dot > 0.999999) {
- out.x = 0;
- out.y = 0;
- out.z = 0;
- out.w = 1;
- return out;
- } else {
- vec3.cross(tmpvec3, a, b);
- out.x = tmpvec3.x;
- out.y = tmpvec3.y;
- out.z = tmpvec3.z;
- out.w = 1 + dot;
- return quat.normalize(out, out);
- }
- };
-})();
-
-/**
- * Gets the rotation axis and angle for a given
- * quaternion. If a quaternion is created with
- * fromAxisAngle, this method will return the same
- * values as providied in the original parameter list
- * OR functionally equivalent values.
- * Example: The quaternion formed by axis [0, 0, 1] and
- * angle -90 is the same as the quaternion formed by
- * [0, 0, 1] and 270. This method favors the latter.
- * @param {vec3} out_axis Vector receiving the axis of rotation
- * @param {quat} q Quaternion to be decomposed
- * @return {Number} Angle, in radians, of the rotation
- */
-quat.getAxisAngle = function (out_axis, q) {
- var rad = Math.acos(q.w) * 2.0;
- var s = Math.sin(rad / 2.0);
- if (s != 0.0) {
- out_axis.x = q.x / s;
- out_axis.y = q.y / s;
- out_axis.z = q.z / s;
- } else {
- // If s is zero, return any axis (no rotation - axis does not matter)
- out_axis.x = 1;
- out_axis.y = 0;
- out_axis.z = 0;
- }
- return rad;
-};
-
-/**
- * Multiplies two quat's
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a the first operand
- * @param {quat} b the second operand
- * @returns {quat} out
- */
-quat.multiply = function (out, a, b) {
- var ax = a.x, ay = a.y, az = a.z, aw = a.w,
- bx = b.x, by = b.y, bz = b.z, bw = b.w;
-
- out.x = ax * bw + aw * bx + ay * bz - az * by;
- out.y = ay * bw + aw * by + az * bx - ax * bz;
- out.z = az * bw + aw * bz + ax * by - ay * bx;
- out.w = aw * bw - ax * bx - ay * by - az * bz;
- return out;
-};
-
-/**
- * Alias for {@link quat.multiply}
- * @function
- */
-quat.mul = quat.multiply;
-
-/**
- * Scales a quat by a scalar number
- *
- * @param {quat} out the receiving vector
- * @param {quat} a the vector to scale
- * @param {Number} b amount to scale the vector by
- * @returns {quat} out
- * @function
- */
-quat.scale = vec4.scale;
-
-/**
- * Rotates a quaternion by the given angle about the X axis
- *
- * @param {quat} out quat receiving operation result
- * @param {quat} a quat to rotate
- * @param {number} rad angle (in radians) to rotate
- * @returns {quat} out
- */
-quat.rotateX = function (out, a, rad) {
- rad *= 0.5;
-
- var ax = a.x, ay = a.y, az = a.z, aw = a.w,
- bx = Math.sin(rad), bw = Math.cos(rad);
-
- out.x = ax * bw + aw * bx;
- out.y = ay * bw + az * bx;
- out.z = az * bw - ay * bx;
- out.w = aw * bw - ax * bx;
- return out;
-};
-
-/**
- * Rotates a quaternion by the given angle about the Y axis
- *
- * @param {quat} out quat receiving operation result
- * @param {quat} a quat to rotate
- * @param {number} rad angle (in radians) to rotate
- * @returns {quat} out
- */
-quat.rotateY = function (out, a, rad) {
- rad *= 0.5;
-
- var ax = a.x, ay = a.y, az = a.z, aw = a.w,
- by = Math.sin(rad), bw = Math.cos(rad);
-
- out.x = ax * bw - az * by;
- out.y = ay * bw + aw * by;
- out.z = az * bw + ax * by;
- out.w = aw * bw - ay * by;
- return out;
-};
-
-/**
- * Rotates a quaternion by the given angle about the Z axis
- *
- * @param {quat} out quat receiving operation result
- * @param {quat} a quat to rotate
- * @param {number} rad angle (in radians) to rotate
- * @returns {quat} out
- */
-quat.rotateZ = function (out, a, rad) {
- rad *= 0.5;
-
- var ax = a.x, ay = a.y, az = a.z, aw = a.w,
- bz = Math.sin(rad), bw = Math.cos(rad);
-
- out.x = ax * bw + ay * bz;
- out.y = ay * bw - ax * bz;
- out.z = az * bw + aw * bz;
- out.w = aw * bw - az * bz;
- return out;
-};
-
-/**
- * Rotates a quaternion by the given angle about the axis in world space
- *
- * @param {quat} out quat receiving operation result
- * @param {quat} rot quat to rotate
- * @param {vec3} axis the axis around which to rotate in world space
- * @param {number} rad angle (in radians) to rotate
- * @returns {quat} out
- */
-quat.rotateAround = (function () {
- var v3_tmp = vec3.create();
- var q_tmp = quat.create();
-
- return function (out, rot, axis, rad) {
- // get inv-axis (local to rot)
- quat.invert(q_tmp, rot);
- vec3.transformQuat(v3_tmp, axis, q_tmp);
- // rotate by inv-axis
- quat.fromAxisAngle(q_tmp, v3_tmp, rad);
- quat.mul(out, rot, q_tmp);
-
- return out;
- };
-})();
-
-/**
- * Rotates a quaternion by the given angle about the axis in local space
- *
- * @param {quat} out quat receiving operation result
- * @param {quat} rot quat to rotate
- * @param {vec3} axis the axis around which to rotate in local space
- * @param {number} rad angle (in radians) to rotate
- * @returns {quat} out
- */
-quat.rotateAroundLocal = (function () {
- var q_tmp = quat.create();
-
- return function (out, rot, axis, rad) {
- quat.fromAxisAngle(q_tmp, axis, rad);
- quat.mul(out, rot, q_tmp);
-
- return out;
- };
-})();
-
-/**
- * Calculates the W component of a quat from the X, Y, and Z components.
- * Assumes that quaternion is 1 unit in length.
- * Any existing W component will be ignored.
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a quat to calculate W component of
- * @returns {quat} out
- */
-quat.calculateW = function (out, a) {
- var x = a.x, y = a.y, z = a.z;
-
- out.x = x;
- out.y = y;
- out.z = z;
- out.w = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
- return out;
-};
-
-/**
- * Calculates the dot product of two quat's
- *
- * @param {quat} a the first operand
- * @param {quat} b the second operand
- * @returns {Number} dot product of a and b
- * @function
- */
-quat.dot = vec4.dot;
-
-/**
- * Performs a linear interpolation between two quat's
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a the first operand
- * @param {quat} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {quat} out
- * @function
- */
-quat.lerp = vec4.lerp;
-
-/**
- * Performs a spherical linear interpolation between two quat
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a the first operand
- * @param {quat} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {quat} out
- */
-quat.slerp = function (out, a, b, t) {
- // benchmarks:
- // http://jsperf.com/quaternion-slerp-implementations
-
- var ax = a.x, ay = a.y, az = a.z, aw = a.w,
- bx = b.x, by = b.y, bz = b.z, bw = b.w;
-
- var omega, cosom, sinom, scale0, scale1;
-
- // calc cosine
- cosom = ax * bx + ay * by + az * bz + aw * bw;
- // adjust signs (if necessary)
- if (cosom < 0.0) {
- cosom = -cosom;
- bx = - bx;
- by = - by;
- bz = - bz;
- bw = - bw;
- }
- // calculate coefficients
- if ((1.0 - cosom) > 0.000001) {
- // standard case (slerp)
- omega = Math.acos(cosom);
- sinom = Math.sin(omega);
- scale0 = Math.sin((1.0 - t) * omega) / sinom;
- scale1 = Math.sin(t * omega) / sinom;
- } else {
- // "from" and "to" quaternions are very close
- // ... so we can do a linear interpolation
- scale0 = 1.0 - t;
- scale1 = t;
- }
- // calculate final values
- out.x = scale0 * ax + scale1 * bx;
- out.y = scale0 * ay + scale1 * by;
- out.z = scale0 * az + scale1 * bz;
- out.w = scale0 * aw + scale1 * bw;
-
- return out;
-};
-
-/**
- * Performs a spherical linear interpolation with two control points
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a the first operand
- * @param {quat} b the second operand
- * @param {quat} c the third operand
- * @param {quat} d the fourth operand
- * @param {Number} t interpolation amount
- * @returns {quat} out
- */
-quat.sqlerp = (function () {
- var temp1 = quat.create();
- var temp2 = quat.create();
-
- return function (out, a, b, c, d, t) {
- quat.slerp(temp1, a, d, t);
- quat.slerp(temp2, b, c, t);
- quat.slerp(out, temp1, temp2, 2 * t * (1 - t));
-
- return out;
- };
-}());
-
-/**
- * Calculates the inverse of a quat
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a quat to calculate inverse of
- * @returns {quat} out
- */
-quat.invert = function (out, a) {
- var a0 = a.x, a1 = a.y, a2 = a.z, a3 = a.w;
- var dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
- var invDot = dot ? 1.0 / dot : 0;
-
- // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
-
- out.x = -a0 * invDot;
- out.y = -a1 * invDot;
- out.z = -a2 * invDot;
- out.w = a3 * invDot;
- return out;
-};
-
-/**
- * Calculates the conjugate of a quat
- * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a quat to calculate conjugate of
- * @returns {quat} out
- */
-quat.conjugate = function (out, a) {
- out.x = -a.x;
- out.y = -a.y;
- out.z = -a.z;
- out.w = a.w;
- return out;
-};
-
-/**
- * Calculates the length of a quat
- *
- * @param {quat} a vector to calculate length of
- * @returns {Number} length of a
- * @function
- */
-quat.length = vec4.length;
-
-/**
- * Alias for {@link quat.length}
- * @function
- */
-quat.len = quat.length;
-
-/**
- * Calculates the squared length of a quat
- *
- * @param {quat} a vector to calculate squared length of
- * @returns {Number} squared length of a
- * @function
- */
-quat.squaredLength = vec4.squaredLength;
-
-/**
- * Alias for {@link quat.squaredLength}
- * @function
- */
-quat.sqrLen = quat.squaredLength;
-
-/**
- * Normalize a quat
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a quaternion to normalize
- * @returns {quat} out
- * @function
- */
-quat.normalize = vec4.normalize;
-
-/**
- * Sets the specified quaternion with values corresponding to the given
- * axes. Each axis is a vec3 and is expected to be unit length and
- * perpendicular to all other specified axes.
- *
- * @param {vec3} xAxis the vector representing the local "right" direction
- * @param {vec3} yAxis the vector representing the local "up" direction
- * @param {vec3} zAxis the vector representing the viewing direction
- * @returns {quat} out
- */
-quat.fromAxes = (function () {
- var matr = mat3.create();
-
- return function (out, xAxis, yAxis, zAxis) {
- mat3.set(
- matr,
- xAxis.x, xAxis.y, xAxis.z,
- yAxis.x, yAxis.y, yAxis.z,
- zAxis.x, zAxis.y, zAxis.z
- );
- return quat.normalize(out, quat.fromMat3(out, matr));
- };
-})();
-
-/**
-* Calculates a quaternion from view direction and up direction
-*
-* @param {quat} out mat3 receiving operation result
-* @param {vec3} view view direction (must be normalized)
-* @param {vec3} [up] up direction, default is (0,1,0) (must be normalized)
-*
-* @returns {quat} out
-*/
-quat.fromViewUp = (function () {
- var matr = mat3.create();
-
- return function (out, view, up) {
- mat3.fromViewUp(matr, view, up);
- if (!matr) {
- return null;
- }
-
- return quat.normalize(out, quat.fromMat3(out, matr));
- };
-})();
-
-/**
- * Sets a quat from the given angle and rotation axis,
- * then returns it.
- *
- * @param {quat} out the receiving quaternion
- * @param {vec3} axis the axis around which to rotate
- * @param {Number} rad the angle in radians
- * @returns {quat} out
- **/
-quat.fromAxisAngle = function (out, axis, rad) {
- rad = rad * 0.5;
- var s = Math.sin(rad);
- out.x = s * axis.x;
- out.y = s * axis.y;
- out.z = s * axis.z;
- out.w = Math.cos(rad);
- return out;
-};
-
-/**
- * Creates a quaternion from the given 3x3 rotation matrix.
- *
- * NOTE: The resultant quaternion is not normalized, so you should be sure
- * to renormalize the quaternion yourself where necessary.
- *
- * @param {quat} out the receiving quaternion
- * @param {mat3} m rotation matrix
- * @returns {quat} out
- * @function
- */
-quat.fromMat3 = function (out, m) {
- // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
-
- var m00 = m.m00, m01 = m.m03, m02 = m.m06,
- m10 = m.m01, m11 = m.m04, m12 = m.m07,
- m20 = m.m02, m21 = m.m05, m22 = m.m08;
-
- var trace = m00 + m11 + m22;
-
- if (trace > 0) {
- var s = 0.5 / Math.sqrt(trace + 1.0);
-
- out.w = 0.25 / s;
- out.x = (m21 - m12) * s;
- out.y = (m02 - m20) * s;
- out.z = (m10 - m01) * s;
-
- } else if ((m00 > m11) && (m00 > m22)) {
- var s$1 = 2.0 * Math.sqrt(1.0 + m00 - m11 - m22);
-
- out.w = (m21 - m12) / s$1;
- out.x = 0.25 * s$1;
- out.y = (m01 + m10) / s$1;
- out.z = (m02 + m20) / s$1;
-
- } else if (m11 > m22) {
- var s$2 = 2.0 * Math.sqrt(1.0 + m11 - m00 - m22);
-
- out.w = (m02 - m20) / s$2;
- out.x = (m01 + m10) / s$2;
- out.y = 0.25 * s$2;
- out.z = (m12 + m21) / s$2;
-
- } else {
- var s$3 = 2.0 * Math.sqrt(1.0 + m22 - m00 - m11);
-
- out.w = (m10 - m01) / s$3;
- out.x = (m02 + m20) / s$3;
- out.y = (m12 + m21) / s$3;
- out.z = 0.25 * s$3;
- }
-
- return out;
-};
-
-/**
- * Creates a quaternion from the given euler angle x, y, z.
- *
- * @param {quat} out the receiving quaternion
- * @param {x} Angle to rotate around X axis in degrees.
- * @param {y} Angle to rotate around Y axis in degrees.
- * @param {z} Angle to rotate around Z axis in degrees.
- * @returns {quat} out
- * @function
- */
-quat.fromEuler = function (out, x, y, z) {
- var halfToRad = 0.5 * Math.PI / 180.0;
- x *= halfToRad;
- y *= halfToRad;
- z *= halfToRad;
-
- var sx = Math.sin(x);
- var cx = Math.cos(x);
- var sy = Math.sin(y);
- var cy = Math.cos(y);
- var sz = Math.sin(z);
- var cz = Math.cos(z);
-
- out.x = sx * cy * cz - cx * sy * sz;
- out.y = cx * sy * cz + sx * cy * sz;
- out.z = cx * cy * sz - sx * sy * cz;
- out.w = cx * cy * cz + sx * sy * sz;
-
- return out;
-};
-
-/**
- * Returns a string representation of a quatenion
- *
- * @param {quat} a vector to represent as a string
- * @returns {String} string representation of the vector
- */
-quat.str = function (a) {
- return ("quat(" + (a.x) + ", " + (a.y) + ", " + (a.z) + ", " + (a.w) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {quat} q
- * @returns {array}
- */
-quat.array = function (out, q) {
- out[0] = q.x;
- out[1] = q.y;
- out[2] = q.z;
- out[3] = q.w;
-
- return out;
-};
-
-/**
- * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)
- *
- * @param {quat} a The first quaternion.
- * @param {quat} b The second quaternion.
- * @returns {Boolean} True if the vectors are equal, false otherwise.
- */
-quat.exactEquals = vec4.exactEquals;
-
-/**
- * Returns whether or not the quaternions have approximately the same elements in the same position.
- *
- * @param {quat} a The first vector.
- * @param {quat} b The second vector.
- * @returns {Boolean} True if the vectors are equal, false otherwise.
- */
-quat.equals = vec4.equals;
-
-var _tmp$5 = new Array(4);
-
-var _mat2 = function _mat2(m00, m01, m02, m03) {
- this.m00 = m00;
- this.m01 = m01;
- this.m02 = m02;
- this.m03 = m03;
-};
-
-_mat2.prototype.toJSON = function toJSON () {
- _tmp$5[0] = this.m00;
- _tmp$5[1] = this.m01;
- _tmp$5[2] = this.m02;
- _tmp$5[3] = this.m03;
-
- return _tmp$5;
-};
-
-/**
- * @class 2x2 Matrix
- * @name mat2
- */
-var mat2 = {};
-
-/**
- * Creates a new identity mat2
- *
- * @returns {mat2} a new 2x2 matrix
- */
-mat2.create = function() {
- return new _mat2(1, 0, 0, 1);
-};
-
-/**
- * Create a new mat2 with the given values
- *
- * @param {Number} m00 Component in column 0, row 0 position (index 0)
- * @param {Number} m01 Component in column 0, row 1 position (index 1)
- * @param {Number} m10 Component in column 1, row 0 position (index 2)
- * @param {Number} m11 Component in column 1, row 1 position (index 3)
- * @returns {mat2} out A new 2x2 matrix
- */
-mat2.new = function (m00, m01, m10, m11) {
- return new _mat2(m00, m01, m10, m11);
-};
-
-/**
- * Creates a new mat2 initialized with values from an existing matrix
- *
- * @param {mat2} a matrix to clone
- * @returns {mat2} a new 2x2 matrix
- */
-mat2.clone = function (a) {
- return new _mat2(a.m00, a.m01, a.m02, a.m03);
-};
-
-/**
- * Copy the values from one mat2 to another
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the source matrix
- * @returns {mat2} out
- */
-mat2.copy = function (out, a) {
- out.m00 = a.m00;
- out.m01 = a.m01;
- out.m02 = a.m02;
- out.m03 = a.m03;
- return out;
-};
-
-/**
- * Set a mat2 to the identity matrix
- *
- * @param {mat2} out the receiving matrix
- * @returns {mat2} out
- */
-mat2.identity = function (out) {
- out.m00 = 1;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 1;
- return out;
-};
-
-/**
- * Set the components of a mat2 to the given values
- *
- * @param {mat2} out the receiving matrix
- * @param {Number} m00 Component in column 0, row 0 position (index 0)
- * @param {Number} m01 Component in column 0, row 1 position (index 1)
- * @param {Number} m10 Component in column 1, row 0 position (index 2)
- * @param {Number} m11 Component in column 1, row 1 position (index 3)
- * @returns {mat2} out
- */
-mat2.set = function (out, m00, m01, m10, m11) {
- out.m00 = m00;
- out.m01 = m01;
- out.m02 = m10;
- out.m03 = m11;
- return out;
-};
-
-
-/**
- * Transpose the values of a mat2
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the source matrix
- * @returns {mat2} out
- */
-mat2.transpose = function (out, a) {
- // If we are transposing ourselves we can skip a few steps but have to cache some values
- if (out === a) {
- var a1 = a.m01;
- out.m01 = a.m02;
- out.m02 = a1;
- } else {
- out.m00 = a.m00;
- out.m01 = a.m02;
- out.m02 = a.m01;
- out.m03 = a.m03;
- }
-
- return out;
-};
-
-/**
- * Inverts a mat2
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the source matrix
- * @returns {mat2} out
- */
-mat2.invert = function (out, a) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03;
-
- // Calculate the determinant
- var det = a0 * a3 - a2 * a1;
-
- if (!det) {
- return null;
- }
- det = 1.0 / det;
-
- out.m00 = a3 * det;
- out.m01 = -a1 * det;
- out.m02 = -a2 * det;
- out.m03 = a0 * det;
-
- return out;
-};
-
-/**
- * Calculates the adjugate of a mat2
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the source matrix
- * @returns {mat2} out
- */
-mat2.adjoint = function (out, a) {
- // Caching this value is nessecary if out == a
- var a0 = a.m00;
- out.m00 = a.m03;
- out.m01 = -a.m01;
- out.m02 = -a.m02;
- out.m03 = a0;
-
- return out;
-};
-
-/**
- * Calculates the determinant of a mat2
- *
- * @param {mat2} a the source matrix
- * @returns {Number} determinant of a
- */
-mat2.determinant = function (a) {
- return a.m00 * a.m03 - a.m02 * a.m01;
-};
-
-/**
- * Multiplies two mat2's
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the first operand
- * @param {mat2} b the second operand
- * @returns {mat2} out
- */
-mat2.multiply = function (out, a, b) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03;
- var b0 = b.m00, b1 = b.m01, b2 = b.m02, b3 = b.m03;
- out.m00 = a0 * b0 + a2 * b1;
- out.m01 = a1 * b0 + a3 * b1;
- out.m02 = a0 * b2 + a2 * b3;
- out.m03 = a1 * b2 + a3 * b3;
- return out;
-};
-
-/**
- * Alias for {@link mat2.multiply}
- * @function
- */
-mat2.mul = mat2.multiply;
-
-/**
- * Rotates a mat2 by the given angle
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat2} out
- */
-mat2.rotate = function (out, a, rad) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03,
- s = Math.sin(rad),
- c = Math.cos(rad);
- out.m00 = a0 * c + a2 * s;
- out.m01 = a1 * c + a3 * s;
- out.m02 = a0 * -s + a2 * c;
- out.m03 = a1 * -s + a3 * c;
- return out;
-};
-
-/**
- * Scales the mat2 by the dimensions in the given vec2
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the matrix to rotate
- * @param {vec2} v the vec2 to scale the matrix by
- * @returns {mat2} out
- **/
-mat2.scale = function (out, a, v) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03,
- v0 = v.x, v1 = v.y;
- out.m00 = a0 * v0;
- out.m01 = a1 * v0;
- out.m02 = a2 * v1;
- out.m03 = a3 * v1;
- return out;
-};
-
-/**
- * Creates a matrix from a given angle
- * This is equivalent to (but much faster than):
- *
- * mat2.identity(dest);
- * mat2.rotate(dest, dest, rad);
- *
- * @param {mat2} out mat2 receiving operation result
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat2} out
- */
-mat2.fromRotation = function (out, rad) {
- var s = Math.sin(rad),
- c = Math.cos(rad);
- out.m00 = c;
- out.m01 = s;
- out.m02 = -s;
- out.m03 = c;
- return out;
-};
-
-/**
- * Creates a matrix from a vector scaling
- * This is equivalent to (but much faster than):
- *
- * mat2.identity(dest);
- * mat2.scale(dest, dest, vec);
- *
- * @param {mat2} out mat2 receiving operation result
- * @param {vec2} v Scaling vector
- * @returns {mat2} out
- */
-mat2.fromScaling = function (out, v) {
- out.m00 = v.x;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = v.y;
- return out;
-};
-
-/**
- * Returns a string representation of a mat2
- *
- * @param {mat2} a matrix to represent as a string
- * @returns {String} string representation of the matrix
- */
-mat2.str = function (a) {
- return ("mat2(" + (a.m00) + ", " + (a.m01) + ", " + (a.m02) + ", " + (a.m03) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {mat2} m
- * @returns {array}
- */
-mat2.array = function (out, m) {
- out[0] = m.m00;
- out[1] = m.m01;
- out[2] = m.m02;
- out[3] = m.m03;
-
- return out;
-};
-
-/**
- * Returns Frobenius norm of a mat2
- *
- * @param {mat2} a the matrix to calculate Frobenius norm of
- * @returns {Number} Frobenius norm
- */
-mat2.frob = function (a) {
- return (Math.sqrt(Math.pow(a.m00, 2) + Math.pow(a.m01, 2) + Math.pow(a.m02, 2) + Math.pow(a.m03, 2)));
-};
-
-/**
- * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
- * @param {mat2} L the lower triangular matrix
- * @param {mat2} D the diagonal matrix
- * @param {mat2} U the upper triangular matrix
- * @param {mat2} a the input matrix to factorize
- */
-
-mat2.LDU = function (L, D, U, a) {
- L.m02 = a.m02 / a.m00;
- U.m00 = a.m00;
- U.m01 = a.m01;
- U.m03 = a.m03 - L.m02 * U.m01;
-};
-
-/**
- * Adds two mat2's
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the first operand
- * @param {mat2} b the second operand
- * @returns {mat2} out
- */
-mat2.add = function (out, a, b) {
- out.m00 = a.m00 + b.m00;
- out.m01 = a.m01 + b.m01;
- out.m02 = a.m02 + b.m02;
- out.m03 = a.m03 + b.m03;
- return out;
-};
-
-/**
- * Subtracts matrix b from matrix a
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the first operand
- * @param {mat2} b the second operand
- * @returns {mat2} out
- */
-mat2.subtract = function (out, a, b) {
- out.m00 = a.m00 - b.m00;
- out.m01 = a.m01 - b.m01;
- out.m02 = a.m02 - b.m02;
- out.m03 = a.m03 - b.m03;
- return out;
-};
-
-/**
- * Alias for {@link mat2.subtract}
- * @function
- */
-mat2.sub = mat2.subtract;
-
-/**
- * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
- *
- * @param {mat2} a The first matrix.
- * @param {mat2} b The second matrix.
- * @returns {Boolean} True if the matrices are equal, false otherwise.
- */
-mat2.exactEquals = function (a, b) {
- return a.m00 === b.m00 && a.m01 === b.m01 && a.m02 === b.m02 && a.m03 === b.m03;
-};
-
-/**
- * Returns whether or not the matrices have approximately the same elements in the same position.
- *
- * @param {mat2} a The first matrix.
- * @param {mat2} b The second matrix.
- * @returns {Boolean} True if the matrices are equal, false otherwise.
- */
-mat2.equals = function (a, b) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03;
- var b0 = b.m00, b1 = b.m01, b2 = b.m02, b3 = b.m03;
- return (
- Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
- Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
- Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3))
- );
-};
-
-/**
- * Multiply each element of the matrix by a scalar.
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the matrix to scale
- * @param {Number} b amount to scale the matrix's elements by
- * @returns {mat2} out
- */
-mat2.multiplyScalar = function (out, a, b) {
- out.m00 = a.m00 * b;
- out.m01 = a.m01 * b;
- out.m02 = a.m02 * b;
- out.m03 = a.m03 * b;
- return out;
-};
-
-/**
- * Adds two mat2's after multiplying each element of the second operand by a scalar value.
- *
- * @param {mat2} out the receiving vector
- * @param {mat2} a the first operand
- * @param {mat2} b the second operand
- * @param {Number} scale the amount to scale b's elements by before adding
- * @returns {mat2} out
- */
-mat2.multiplyScalarAndAdd = function (out, a, b, scale) {
- out.m00 = a.m00 + (b.m00 * scale);
- out.m01 = a.m01 + (b.m01 * scale);
- out.m02 = a.m02 + (b.m02 * scale);
- out.m03 = a.m03 + (b.m03 * scale);
- return out;
-};
-
-var _tmp$6 = new Array(6);
-
-var _mat23 = function _mat23(m00, m01, m02, m03, m04, m05) {
- this.m00 = m00;
- this.m01 = m01;
- this.m02 = m02;
- this.m03 = m03;
- this.m04 = m04;
- this.m05 = m05;
-};
-
-_mat23.prototype.toJSON = function toJSON () {
- _tmp$6[0] = this.m00;
- _tmp$6[1] = this.m01;
- _tmp$6[2] = this.m02;
- _tmp$6[3] = this.m03;
- _tmp$6[4] = this.m04;
- _tmp$6[5] = this.m05;
-
- return _tmp$6;
-};
-
-/**
- * @class 2x3 Matrix
- * @name mat23
- *
- * @description
- * A mat23 contains six elements defined as:
- *
- * [a, c, tx,
- * b, d, ty]
- *
- * This is a short form for the 3x3 matrix:
- *
- * [a, c, tx,
- * b, d, ty,
- * 0, 0, 1]
- *
- * The last row is ignored so the array is shorter and operations are faster.
- */
-var mat23 = {};
-
-/**
- * Creates a new identity mat23
- *
- * @returns {mat23} a new 2x3 matrix
- */
-mat23.create = function () {
- return new _mat23(
- 1, 0,
- 0, 1,
- 0, 0
- );
-};
-
-/**
- * Create a new mat23 with the given values
- *
- * @param {Number} a Component A (index 0)
- * @param {Number} b Component B (index 1)
- * @param {Number} c Component C (index 2)
- * @param {Number} d Component D (index 3)
- * @param {Number} tx Component TX (index 4)
- * @param {Number} ty Component TY (index 5)
- * @returns {mat23} A new mat23
- */
-mat23.new = function (a, b, c, d, tx, ty) {
- return new _mat23(
- a, b,
- c, d,
- tx, ty
- );
-};
-
-/**
- * Creates a new mat23 initialized with values from an existing matrix
- *
- * @param {mat23} a matrix to clone
- * @returns {mat23} a new 2x3 matrix
- */
-mat23.clone = function (a) {
- return new _mat23(
- a.m00, a.m01,
- a.m02, a.m03,
- a.m04, a.m05
- );
-};
-
-/**
- * Copy the values from one mat23 to another
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the source matrix
- * @returns {mat23} out
- */
-mat23.copy = function (out, a) {
- out.m00 = a.m00;
- out.m01 = a.m01;
- out.m02 = a.m02;
- out.m03 = a.m03;
- out.m04 = a.m04;
- out.m05 = a.m05;
- return out;
-};
-
-/**
- * Set a mat23 to the identity matrix
- *
- * @param {mat23} out the receiving matrix
- * @returns {mat23} out
- */
-mat23.identity = function (out) {
- out.m00 = 1;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 1;
- out.m04 = 0;
- out.m05 = 0;
- return out;
-};
-
-/**
- * Set the components of a mat23 to the given values
- *
- * @param {mat23} out the receiving matrix
- * @param {Number} a Component A (index 0)
- * @param {Number} b Component B (index 1)
- * @param {Number} c Component C (index 2)
- * @param {Number} d Component D (index 3)
- * @param {Number} tx Component TX (index 4)
- * @param {Number} ty Component TY (index 5)
- * @returns {mat23} out
- */
-mat23.set = function (out, a, b, c, d, tx, ty) {
- out.m00 = a;
- out.m01 = b;
- out.m02 = c;
- out.m03 = d;
- out.m04 = tx;
- out.m05 = ty;
- return out;
-};
-
-/**
- * Inverts a mat23
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the source matrix
- * @returns {mat23} out
- */
-mat23.invert = function (out, a) {
- var aa = a.m00, ab = a.m01, ac = a.m02, ad = a.m03,
- atx = a.m04, aty = a.m05;
-
- var det = aa * ad - ab * ac;
- if (!det) {
- return null;
- }
- det = 1.0 / det;
-
- out.m00 = ad * det;
- out.m01 = -ab * det;
- out.m02 = -ac * det;
- out.m03 = aa * det;
- out.m04 = (ac * aty - ad * atx) * det;
- out.m05 = (ab * atx - aa * aty) * det;
- return out;
-};
-
-/**
- * Calculates the determinant of a mat23
- *
- * @param {mat23} a the source matrix
- * @returns {Number} determinant of a
- */
-mat23.determinant = function (a) {
- return a.m00 * a.m03 - a.m01 * a.m02;
-};
-
-/**
- * Multiplies two mat23's
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the first operand
- * @param {mat23} b the second operand
- * @returns {mat23} out
- */
-mat23.multiply = function (out, a, b) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03, a4 = a.m04, a5 = a.m05,
- b0 = b.m00, b1 = b.m01, b2 = b.m02, b3 = b.m03, b4 = b.m04, b5 = b.m05;
- out.m00 = a0 * b0 + a2 * b1;
- out.m01 = a1 * b0 + a3 * b1;
- out.m02 = a0 * b2 + a2 * b3;
- out.m03 = a1 * b2 + a3 * b3;
- out.m04 = a0 * b4 + a2 * b5 + a4;
- out.m05 = a1 * b4 + a3 * b5 + a5;
- return out;
-};
-
-/**
- * Alias for {@link mat23.multiply}
- * @function
- */
-mat23.mul = mat23.multiply;
-
-/**
- * Rotates a mat23 by the given angle
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat23} out
- */
-mat23.rotate = function (out, a, rad) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03, a4 = a.m04, a5 = a.m05,
- s = Math.sin(rad),
- c = Math.cos(rad);
- out.m00 = a0 * c + a2 * s;
- out.m01 = a1 * c + a3 * s;
- out.m02 = a0 * -s + a2 * c;
- out.m03 = a1 * -s + a3 * c;
- out.m04 = a4;
- out.m05 = a5;
- return out;
-};
-
-/**
- * Scales the mat23 by the dimensions in the given vec2
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the matrix to translate
- * @param {vec2} v the vec2 to scale the matrix by
- * @returns {mat23} out
- **/
-mat23.scale = function (out, a, v) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03, a4 = a.m04, a5 = a.m05,
- v0 = v.x, v1 = v.y;
- out.m00 = a0 * v0;
- out.m01 = a1 * v0;
- out.m02 = a2 * v1;
- out.m03 = a3 * v1;
- out.m04 = a4;
- out.m05 = a5;
- return out;
-};
-
-/**
- * Translates the mat23 by the dimensions in the given vec2
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the matrix to translate
- * @param {vec2} v the vec2 to translate the matrix by
- * @returns {mat23} out
- **/
-mat23.translate = function (out, a, v) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03, a4 = a.m04, a5 = a.m05,
- v0 = v.x, v1 = v.y;
- out.m00 = a0;
- out.m01 = a1;
- out.m02 = a2;
- out.m03 = a3;
- out.m04 = a0 * v0 + a2 * v1 + a4;
- out.m05 = a1 * v0 + a3 * v1 + a5;
- return out;
-};
-
-/**
- * Creates a matrix from a given angle
- * This is equivalent to (but much faster than):
- *
- * mat23.identity(dest);
- * mat23.rotate(dest, dest, rad);
- *
- * @param {mat23} out mat23 receiving operation result
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat23} out
- */
-mat23.fromRotation = function (out, rad) {
- var s = Math.sin(rad), c = Math.cos(rad);
- out.m00 = c;
- out.m01 = s;
- out.m02 = -s;
- out.m03 = c;
- out.m04 = 0;
- out.m05 = 0;
- return out;
-};
-
-/**
- * Creates a matrix from a vector scaling
- * This is equivalent to (but much faster than):
- *
- * mat23.identity(dest);
- * mat23.scale(dest, dest, vec);
- *
- * @param {mat23} out mat23 receiving operation result
- * @param {vec2} v Scaling vector
- * @returns {mat23} out
- */
-mat23.fromScaling = function (out, v) {
- out.m00 = v.m00;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = v.m01;
- out.m04 = 0;
- out.m05 = 0;
- return out;
-};
-
-/**
- * Creates a matrix from a vector translation
- * This is equivalent to (but much faster than):
- *
- * mat23.identity(dest);
- * mat23.translate(dest, dest, vec);
- *
- * @param {mat23} out mat23 receiving operation result
- * @param {vec2} v Translation vector
- * @returns {mat23} out
- */
-mat23.fromTranslation = function (out, v) {
- out.m00 = 1;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 1;
- out.m04 = v.x;
- out.m05 = v.y;
- return out;
-};
-
-/**
- * Returns a string representation of a mat23
- *
- * @param {mat23} a matrix to represent as a string
- * @returns {String} string representation of the matrix
- */
-mat23.str = function (a) {
- return ("mat23(" + (a.m00) + ", " + (a.m01) + ", " + (a.m02) + ", " + (a.m03) + ", " + (a.m04) + ", " + (a.m05) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {mat23} m
- * @returns {array}
- */
-mat23.array = function (out, m) {
- out[0] = m.m00;
- out[1] = m.m01;
- out[2] = m.m02;
- out[3] = m.m03;
- out[4] = m.m04;
- out[5] = m.m05;
-
- return out;
-};
-
-/**
- * Returns typed array to 16 float array
- *
- * @param {array} out
- * @param {mat23} m
- * @returns {array}
- */
-mat23.array4x4 = function (out, m) {
- out[0] = m.m00;
- out[1] = m.m01;
- out[2] = 0;
- out[3] = 0;
- out[4] = m.m02;
- out[5] = m.m03;
- out[6] = 0;
- out[7] = 0;
- out[8] = 0;
- out[9] = 0;
- out[10] = 1;
- out[11] = 0;
- out[12] = m.m04;
- out[13] = m.m05;
- out[14] = 0;
- out[15] = 1;
-
- return out;
-};
-
-/**
- * Returns Frobenius norm of a mat23
- *
- * @param {mat23} a the matrix to calculate Frobenius norm of
- * @returns {Number} Frobenius norm
- */
-mat23.frob = function (a) {
- return (Math.sqrt(Math.pow(a.m00, 2) + Math.pow(a.m01, 2) + Math.pow(a.m02, 2) + Math.pow(a.m03, 2) + Math.pow(a.m04, 2) + Math.pow(a.m05, 2) + 1));
-};
-
-/**
- * Adds two mat23's
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the first operand
- * @param {mat23} b the second operand
- * @returns {mat23} out
- */
-mat23.add = function (out, a, b) {
- out.m00 = a.m00 + b.m00;
- out.m01 = a.m01 + b.m01;
- out.m02 = a.m02 + b.m02;
- out.m03 = a.m03 + b.m03;
- out.m04 = a.m04 + b.m04;
- out.m05 = a.m05 + b.m05;
- return out;
-};
-
-/**
- * Subtracts matrix b from matrix a
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the first operand
- * @param {mat23} b the second operand
- * @returns {mat23} out
- */
-mat23.subtract = function (out, a, b) {
- out.m00 = a.m00 - b.m00;
- out.m01 = a.m01 - b.m01;
- out.m02 = a.m02 - b.m02;
- out.m03 = a.m03 - b.m03;
- out.m04 = a.m04 - b.m04;
- out.m05 = a.m05 - b.m05;
- return out;
-};
-
-/**
- * Alias for {@link mat23.subtract}
- * @function
- */
-mat23.sub = mat23.subtract;
-
-/**
- * Multiply each element of the matrix by a scalar.
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the matrix to scale
- * @param {Number} b amount to scale the matrix's elements by
- * @returns {mat23} out
- */
-mat23.multiplyScalar = function (out, a, b) {
- out.m00 = a.m00 * b;
- out.m01 = a.m01 * b;
- out.m02 = a.m02 * b;
- out.m03 = a.m03 * b;
- out.m04 = a.m04 * b;
- out.m05 = a.m05 * b;
- return out;
-};
-
-/**
- * Adds two mat23's after multiplying each element of the second operand by a scalar value.
- *
- * @param {mat23} out the receiving vector
- * @param {mat23} a the first operand
- * @param {mat23} b the second operand
- * @param {Number} scale the amount to scale b's elements by before adding
- * @returns {mat23} out
- */
-mat23.multiplyScalarAndAdd = function (out, a, b, scale) {
- out.m00 = a.m00 + (b.m00 * scale);
- out.m01 = a.m01 + (b.m01 * scale);
- out.m02 = a.m02 + (b.m02 * scale);
- out.m03 = a.m03 + (b.m03 * scale);
- out.m04 = a.m04 + (b.m04 * scale);
- out.m05 = a.m05 + (b.m05 * scale);
- return out;
-};
-
-/**
- * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
- *
- * @param {mat23} a The first matrix.
- * @param {mat23} b The second matrix.
- * @returns {Boolean} True if the matrices are equal, false otherwise.
- */
-mat23.exactEquals = function (a, b) {
- return a.m00 === b.m00 && a.m01 === b.m01 && a.m02 === b.m02 && a.m03 === b.m03 && a.m04 === b.m04 && a.m05 === b.m05;
-};
-
-/**
- * Returns whether or not the matrices have approximately the same elements in the same position.
- *
- * @param {mat23} a The first matrix.
- * @param {mat23} b The second matrix.
- * @returns {Boolean} True if the matrices are equal, false otherwise.
- */
-mat23.equals = function (a, b) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03, a4 = a.m04, a5 = a.m05;
- var b0 = b.m00, b1 = b.m01, b2 = b.m02, b3 = b.m03, b4 = b.m04, b5 = b.m05;
- return (
- Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
- Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
- Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&
- Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&
- Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5))
- );
-};
-
-var _tmp$7 = new Array(16);
-
-var _mat4 = function _mat4(
- m00, m01, m02, m03,
- m04, m05, m06, m07,
- m08, m09, m10, m11,
- m12, m13, m14, m15
-) {
- this.m00 = m00;
- this.m01 = m01;
- this.m02 = m02;
- this.m03 = m03;
- this.m04 = m04;
- this.m05 = m05;
- this.m06 = m06;
- this.m07 = m07;
- this.m08 = m08;
- this.m09 = m09;
- this.m10 = m10;
- this.m11 = m11;
- this.m12 = m12;
- this.m13 = m13;
- this.m14 = m14;
- this.m15 = m15;
-};
-
-_mat4.prototype.toJSON = function toJSON () {
- _tmp$7[0] = this.m00;
- _tmp$7[1] = this.m01;
- _tmp$7[2] = this.m02;
- _tmp$7[3] = this.m03;
- _tmp$7[4] = this.m04;
- _tmp$7[5] = this.m05;
- _tmp$7[6] = this.m06;
- _tmp$7[7] = this.m07;
- _tmp$7[8] = this.m08;
- _tmp$7[9] = this.m09;
- _tmp$7[10] = this.m10;
- _tmp$7[11] = this.m11;
- _tmp$7[12] = this.m12;
- _tmp$7[13] = this.m13;
- _tmp$7[14] = this.m14;
- _tmp$7[15] = this.m15;
-
- return _tmp$7;
-};
-
-/**
- * @class 4x4 Matrix
- * @name mat4
- *
- * NOTE: we use column-major matrix for all matrix calculation.
- *
- * This may lead to some confusion when referencing OpenGL documentation,
- * however, which represents out all matricies in column-major format.
- * This means that while in code a matrix may be typed out as:
- *
- * [1, 0, 0, 0,
- * 0, 1, 0, 0,
- * 0, 0, 1, 0,
- * x, y, z, 0]
- *
- * The same matrix in the [OpenGL documentation](https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTranslate.xml)
- * is written as:
- *
- * 1 0 0 x
- * 0 1 0 y
- * 0 0 1 z
- * 0 0 0 0
- *
- * Please rest assured, however, that they are the same thing!
- * This is not unique to glMatrix, either, as OpenGL developers have long been confused by the
- * apparent lack of consistency between the memory layout and the documentation.
- */
-var mat4 = {};
-
-/**
- * Creates a new identity mat4
- *
- * @returns {mat4} a new 4x4 matrix
- */
-mat4.create = function () {
- return new _mat4(
- 1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1
- );
-};
-
-/**
- * Create a new mat4 with the given values
- *
- * @param {Number} m00 Component in column 0, row 0 position (index 0)
- * @param {Number} m01 Component in column 0, row 1 position (index 1)
- * @param {Number} m02 Component in column 0, row 2 position (index 2)
- * @param {Number} m03 Component in column 0, row 3 position (index 3)
- * @param {Number} m10 Component in column 1, row 0 position (index 4)
- * @param {Number} m11 Component in column 1, row 1 position (index 5)
- * @param {Number} m12 Component in column 1, row 2 position (index 6)
- * @param {Number} m13 Component in column 1, row 3 position (index 7)
- * @param {Number} m20 Component in column 2, row 0 position (index 8)
- * @param {Number} m21 Component in column 2, row 1 position (index 9)
- * @param {Number} m22 Component in column 2, row 2 position (index 10)
- * @param {Number} m23 Component in column 2, row 3 position (index 11)
- * @param {Number} m30 Component in column 3, row 0 position (index 12)
- * @param {Number} m31 Component in column 3, row 1 position (index 13)
- * @param {Number} m32 Component in column 3, row 2 position (index 14)
- * @param {Number} m33 Component in column 3, row 3 position (index 15)
- * @returns {mat4} A new mat4
- */
-mat4.new = function (m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
- return new _mat4(
- m00, m01, m02, m03,
- m10, m11, m12, m13,
- m20, m21, m22, m23,
- m30, m31, m32, m33
- );
-};
-
-/**
- * Creates a new mat4 initialized with values from an existing matrix
- *
- * @param {mat4} a matrix to clone
- * @returns {mat4} a new 4x4 matrix
- */
-mat4.clone = function (a) {
- return new _mat4(
- a.m00, a.m01, a.m02, a.m03,
- a.m04, a.m05, a.m06, a.m07,
- a.m08, a.m09, a.m10, a.m11,
- a.m12, a.m13, a.m14, a.m15
- );
-};
-
-/**
- * Copy the values from one mat4 to another
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the source matrix
- * @returns {mat4} out
- */
-mat4.copy = function (out, a) {
- out.m00 = a.m00;
- out.m01 = a.m01;
- out.m02 = a.m02;
- out.m03 = a.m03;
- out.m04 = a.m04;
- out.m05 = a.m05;
- out.m06 = a.m06;
- out.m07 = a.m07;
- out.m08 = a.m08;
- out.m09 = a.m09;
- out.m10 = a.m10;
- out.m11 = a.m11;
- out.m12 = a.m12;
- out.m13 = a.m13;
- out.m14 = a.m14;
- out.m15 = a.m15;
- return out;
-};
-
-/**
- * Set the components of a mat4 to the given values
- *
- * @param {mat4} out the receiving matrix
- * @param {Number} m00 Component in column 0, row 0 position (index 0)
- * @param {Number} m01 Component in column 0, row 1 position (index 1)
- * @param {Number} m02 Component in column 0, row 2 position (index 2)
- * @param {Number} m03 Component in column 0, row 3 position (index 3)
- * @param {Number} m10 Component in column 1, row 0 position (index 4)
- * @param {Number} m11 Component in column 1, row 1 position (index 5)
- * @param {Number} m12 Component in column 1, row 2 position (index 6)
- * @param {Number} m13 Component in column 1, row 3 position (index 7)
- * @param {Number} m20 Component in column 2, row 0 position (index 8)
- * @param {Number} m21 Component in column 2, row 1 position (index 9)
- * @param {Number} m22 Component in column 2, row 2 position (index 10)
- * @param {Number} m23 Component in column 2, row 3 position (index 11)
- * @param {Number} m30 Component in column 3, row 0 position (index 12)
- * @param {Number} m31 Component in column 3, row 1 position (index 13)
- * @param {Number} m32 Component in column 3, row 2 position (index 14)
- * @param {Number} m33 Component in column 3, row 3 position (index 15)
- * @returns {mat4} out
- */
-mat4.set = function (out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
- out.m00 = m00;
- out.m01 = m01;
- out.m02 = m02;
- out.m03 = m03;
- out.m04 = m10;
- out.m05 = m11;
- out.m06 = m12;
- out.m07 = m13;
- out.m08 = m20;
- out.m09 = m21;
- out.m10 = m22;
- out.m11 = m23;
- out.m12 = m30;
- out.m13 = m31;
- out.m14 = m32;
- out.m15 = m33;
- return out;
-};
-
-
-/**
- * Set a mat4 to the identity matrix
- *
- * @param {mat4} out the receiving matrix
- * @returns {mat4} out
- */
-mat4.identity = function (out) {
- out.m00 = 1;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 0;
- out.m05 = 1;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 0;
- out.m09 = 0;
- out.m10 = 1;
- out.m11 = 0;
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = 0;
- out.m15 = 1;
- return out;
-};
-
-/**
- * Transpose the values of a mat4
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the source matrix
- * @returns {mat4} out
- */
-mat4.transpose = function (out, a) {
- // If we are transposing ourselves we can skip a few steps but have to cache some values
- if (out === a) {
- var a01 = a.m01, a02 = a.m02, a03 = a.m03,
- a12 = a.m06, a13 = a.m07,
- a23 = a.m11;
-
- out.m01 = a.m04;
- out.m02 = a.m08;
- out.m03 = a.m12;
- out.m04 = a01;
- out.m06 = a.m09;
- out.m07 = a.m13;
- out.m08 = a02;
- out.m09 = a12;
- out.m11 = a.m14;
- out.m12 = a03;
- out.m13 = a13;
- out.m14 = a23;
- } else {
- out.m00 = a.m00;
- out.m01 = a.m04;
- out.m02 = a.m08;
- out.m03 = a.m12;
- out.m04 = a.m01;
- out.m05 = a.m05;
- out.m06 = a.m09;
- out.m07 = a.m13;
- out.m08 = a.m02;
- out.m09 = a.m06;
- out.m10 = a.m10;
- out.m11 = a.m14;
- out.m12 = a.m03;
- out.m13 = a.m07;
- out.m14 = a.m11;
- out.m15 = a.m15;
- }
-
- return out;
-};
-
-/**
- * Inverts a mat4
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the source matrix
- * @returns {mat4} out
- */
-mat4.invert = function (out, a) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02, a03 = a.m03,
- a10 = a.m04, a11 = a.m05, a12 = a.m06, a13 = a.m07,
- a20 = a.m08, a21 = a.m09, a22 = a.m10, a23 = a.m11,
- a30 = a.m12, a31 = a.m13, a32 = a.m14, a33 = a.m15;
-
- var b00 = a00 * a11 - a01 * a10;
- var b01 = a00 * a12 - a02 * a10;
- var b02 = a00 * a13 - a03 * a10;
- var b03 = a01 * a12 - a02 * a11;
- var b04 = a01 * a13 - a03 * a11;
- var b05 = a02 * a13 - a03 * a12;
- var b06 = a20 * a31 - a21 * a30;
- var b07 = a20 * a32 - a22 * a30;
- var b08 = a20 * a33 - a23 * a30;
- var b09 = a21 * a32 - a22 * a31;
- var b10 = a21 * a33 - a23 * a31;
- var b11 = a22 * a33 - a23 * a32;
-
- // Calculate the determinant
- var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
-
- if (!det) {
- return null;
- }
- det = 1.0 / det;
-
- out.m00 = (a11 * b11 - a12 * b10 + a13 * b09) * det;
- out.m01 = (a02 * b10 - a01 * b11 - a03 * b09) * det;
- out.m02 = (a31 * b05 - a32 * b04 + a33 * b03) * det;
- out.m03 = (a22 * b04 - a21 * b05 - a23 * b03) * det;
- out.m04 = (a12 * b08 - a10 * b11 - a13 * b07) * det;
- out.m05 = (a00 * b11 - a02 * b08 + a03 * b07) * det;
- out.m06 = (a32 * b02 - a30 * b05 - a33 * b01) * det;
- out.m07 = (a20 * b05 - a22 * b02 + a23 * b01) * det;
- out.m08 = (a10 * b10 - a11 * b08 + a13 * b06) * det;
- out.m09 = (a01 * b08 - a00 * b10 - a03 * b06) * det;
- out.m10 = (a30 * b04 - a31 * b02 + a33 * b00) * det;
- out.m11 = (a21 * b02 - a20 * b04 - a23 * b00) * det;
- out.m12 = (a11 * b07 - a10 * b09 - a12 * b06) * det;
- out.m13 = (a00 * b09 - a01 * b07 + a02 * b06) * det;
- out.m14 = (a31 * b01 - a30 * b03 - a32 * b00) * det;
- out.m15 = (a20 * b03 - a21 * b01 + a22 * b00) * det;
-
- return out;
-};
-
-/**
- * Calculates the adjugate of a mat4
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the source matrix
- * @returns {mat4} out
- */
-mat4.adjoint = function (out, a) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02, a03 = a.m03,
- a10 = a.m04, a11 = a.m05, a12 = a.m06, a13 = a.m07,
- a20 = a.m08, a21 = a.m09, a22 = a.m10, a23 = a.m11,
- a30 = a.m12, a31 = a.m13, a32 = a.m14, a33 = a.m15;
-
- out.m00 = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22));
- out.m01 = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
- out.m02 = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12));
- out.m03 = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
- out.m04 = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
- out.m05 = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22));
- out.m06 = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
- out.m07 = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12));
- out.m08 = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21));
- out.m09 = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
- out.m10 = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11));
- out.m11 = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
- out.m12 = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
- out.m13 = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21));
- out.m14 = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
- out.m15 = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11));
- return out;
-};
-
-/**
- * Calculates the determinant of a mat4
- *
- * @param {mat4} a the source matrix
- * @returns {Number} determinant of a
- */
-mat4.determinant = function (a) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02, a03 = a.m03,
- a10 = a.m04, a11 = a.m05, a12 = a.m06, a13 = a.m07,
- a20 = a.m08, a21 = a.m09, a22 = a.m10, a23 = a.m11,
- a30 = a.m12, a31 = a.m13, a32 = a.m14, a33 = a.m15;
-
- var b00 = a00 * a11 - a01 * a10;
- var b01 = a00 * a12 - a02 * a10;
- var b02 = a00 * a13 - a03 * a10;
- var b03 = a01 * a12 - a02 * a11;
- var b04 = a01 * a13 - a03 * a11;
- var b05 = a02 * a13 - a03 * a12;
- var b06 = a20 * a31 - a21 * a30;
- var b07 = a20 * a32 - a22 * a30;
- var b08 = a20 * a33 - a23 * a30;
- var b09 = a21 * a32 - a22 * a31;
- var b10 = a21 * a33 - a23 * a31;
- var b11 = a22 * a33 - a23 * a32;
-
- // Calculate the determinant
- return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
-};
-
-/**
- * Multiplies two mat4's explicitly
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the first operand
- * @param {mat4} b the second operand
- * @returns {mat4} out
- */
-mat4.multiply = function (out, a, b) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02, a03 = a.m03,
- a10 = a.m04, a11 = a.m05, a12 = a.m06, a13 = a.m07,
- a20 = a.m08, a21 = a.m09, a22 = a.m10, a23 = a.m11,
- a30 = a.m12, a31 = a.m13, a32 = a.m14, a33 = a.m15;
-
- // Cache only the current line of the second matrix
- var b0 = b.m00, b1 = b.m01, b2 = b.m02, b3 = b.m03;
- out.m00 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
- out.m01 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
- out.m02 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
- out.m03 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
-
- b0 = b.m04; b1 = b.m05; b2 = b.m06; b3 = b.m07;
- out.m04 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
- out.m05 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
- out.m06 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
- out.m07 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
-
- b0 = b.m08; b1 = b.m09; b2 = b.m10; b3 = b.m11;
- out.m08 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
- out.m09 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
- out.m10 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
- out.m11 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
-
- b0 = b.m12; b1 = b.m13; b2 = b.m14; b3 = b.m15;
- out.m12 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
- out.m13 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
- out.m14 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
- out.m15 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
- return out;
-};
-
-/**
- * Alias for {@link mat4.multiply}
- * @function
- */
-mat4.mul = mat4.multiply;
-
-/**
- * Translate a mat4 by the given vector
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the matrix to translate
- * @param {vec3} v vector to translate by
- * @returns {mat4} out
- */
-mat4.translate = function (out, a, v) {
- var x = v.x, y = v.y, z = v.z,
- a00, a01, a02, a03,
- a10, a11, a12, a13,
- a20, a21, a22, a23;
-
- if (a === out) {
- out.m12 = a.m00 * x + a.m04 * y + a.m08 * z + a.m12;
- out.m13 = a.m01 * x + a.m05 * y + a.m09 * z + a.m13;
- out.m14 = a.m02 * x + a.m06 * y + a.m10 * z + a.m14;
- out.m15 = a.m03 * x + a.m07 * y + a.m11 * z + a.m15;
- } else {
- a00 = a.m00; a01 = a.m01; a02 = a.m02; a03 = a.m03;
- a10 = a.m04; a11 = a.m05; a12 = a.m06; a13 = a.m07;
- a20 = a.m08; a21 = a.m09; a22 = a.m10; a23 = a.m11;
-
- out.m00 = a00; out.m01 = a01; out.m02 = a02; out.m03 = a03;
- out.m04 = a10; out.m05 = a11; out.m06 = a12; out.m07 = a13;
- out.m08 = a20; out.m09 = a21; out.m10 = a22; out.m11 = a23;
-
- out.m12 = a00 * x + a10 * y + a20 * z + a.m12;
- out.m13 = a01 * x + a11 * y + a21 * z + a.m13;
- out.m14 = a02 * x + a12 * y + a22 * z + a.m14;
- out.m15 = a03 * x + a13 * y + a23 * z + a.m15;
- }
-
- return out;
-};
-
-/**
- * Scales the mat4 by the dimensions in the given vec3
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the matrix to scale
- * @param {vec3} v the vec3 to scale the matrix by
- * @returns {mat4} out
- **/
-mat4.scale = function (out, a, v) {
- var x = v.x, y = v.y, z = v.z;
-
- out.m00 = a.m00 * x;
- out.m01 = a.m01 * x;
- out.m02 = a.m02 * x;
- out.m03 = a.m03 * x;
- out.m04 = a.m04 * y;
- out.m05 = a.m05 * y;
- out.m06 = a.m06 * y;
- out.m07 = a.m07 * y;
- out.m08 = a.m08 * z;
- out.m09 = a.m09 * z;
- out.m10 = a.m10 * z;
- out.m11 = a.m11 * z;
- out.m12 = a.m12;
- out.m13 = a.m13;
- out.m14 = a.m14;
- out.m15 = a.m15;
- return out;
-};
-
-/**
- * Rotates a mat4 by the given angle around the given axis
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @param {vec3} axis the axis to rotate around
- * @returns {mat4} out
- */
-mat4.rotate = function (out, a, rad, axis) {
- var x = axis.x, y = axis.y, z = axis.z;
- var s, c, t,
- a00, a01, a02, a03,
- a10, a11, a12, a13,
- a20, a21, a22, a23,
- b00, b01, b02,
- b10, b11, b12,
- b20, b21, b22;
-
- var len = Math.sqrt(x * x + y * y + z * z);
-
- if (Math.abs(len) < EPSILON) {
- return null;
- }
-
- len = 1 / len;
- x *= len;
- y *= len;
- z *= len;
-
- s = Math.sin(rad);
- c = Math.cos(rad);
- t = 1 - c;
-
- a00 = a.m00; a01 = a.m01; a02 = a.m02; a03 = a.m03;
- a10 = a.m04; a11 = a.m05; a12 = a.m06; a13 = a.m07;
- a20 = a.m08; a21 = a.m09; a22 = a.m10; a23 = a.m11;
-
- // Construct the elements of the rotation matrix
- b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;
- b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;
- b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;
-
- // Perform rotation-specific matrix multiplication
- out.m00 = a00 * b00 + a10 * b01 + a20 * b02;
- out.m01 = a01 * b00 + a11 * b01 + a21 * b02;
- out.m02 = a02 * b00 + a12 * b01 + a22 * b02;
- out.m03 = a03 * b00 + a13 * b01 + a23 * b02;
- out.m04 = a00 * b10 + a10 * b11 + a20 * b12;
- out.m05 = a01 * b10 + a11 * b11 + a21 * b12;
- out.m06 = a02 * b10 + a12 * b11 + a22 * b12;
- out.m07 = a03 * b10 + a13 * b11 + a23 * b12;
- out.m08 = a00 * b20 + a10 * b21 + a20 * b22;
- out.m09 = a01 * b20 + a11 * b21 + a21 * b22;
- out.m10 = a02 * b20 + a12 * b21 + a22 * b22;
- out.m11 = a03 * b20 + a13 * b21 + a23 * b22;
-
- // If the source and destination differ, copy the unchanged last row
- if (a !== out) {
- out.m12 = a.m12;
- out.m13 = a.m13;
- out.m14 = a.m14;
- out.m15 = a.m15;
- }
-
- return out;
-};
-
-/**
- * Rotates a matrix by the given angle around the X axis
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat4} out
- */
-mat4.rotateX = function (out, a, rad) {
- var s = Math.sin(rad),
- c = Math.cos(rad),
- a10 = a.m04,
- a11 = a.m05,
- a12 = a.m06,
- a13 = a.m07,
- a20 = a.m08,
- a21 = a.m09,
- a22 = a.m10,
- a23 = a.m11;
-
- if (a !== out) { // If the source and destination differ, copy the unchanged rows
- out.m00 = a.m00;
- out.m01 = a.m01;
- out.m02 = a.m02;
- out.m03 = a.m03;
- out.m12 = a.m12;
- out.m13 = a.m13;
- out.m14 = a.m14;
- out.m15 = a.m15;
- }
-
- // Perform axis-specific matrix multiplication
- out.m04 = a10 * c + a20 * s;
- out.m05 = a11 * c + a21 * s;
- out.m06 = a12 * c + a22 * s;
- out.m07 = a13 * c + a23 * s;
- out.m08 = a20 * c - a10 * s;
- out.m09 = a21 * c - a11 * s;
- out.m10 = a22 * c - a12 * s;
- out.m11 = a23 * c - a13 * s;
-
- return out;
-};
-
-/**
- * Rotates a matrix by the given angle around the Y axis
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat4} out
- */
-mat4.rotateY = function (out, a, rad) {
- var s = Math.sin(rad),
- c = Math.cos(rad),
- a00 = a.m00,
- a01 = a.m01,
- a02 = a.m02,
- a03 = a.m03,
- a20 = a.m08,
- a21 = a.m09,
- a22 = a.m10,
- a23 = a.m11;
-
- if (a !== out) { // If the source and destination differ, copy the unchanged rows
- out.m04 = a.m04;
- out.m05 = a.m05;
- out.m06 = a.m06;
- out.m07 = a.m07;
- out.m12 = a.m12;
- out.m13 = a.m13;
- out.m14 = a.m14;
- out.m15 = a.m15;
- }
-
- // Perform axis-specific matrix multiplication
- out.m00 = a00 * c - a20 * s;
- out.m01 = a01 * c - a21 * s;
- out.m02 = a02 * c - a22 * s;
- out.m03 = a03 * c - a23 * s;
- out.m08 = a00 * s + a20 * c;
- out.m09 = a01 * s + a21 * c;
- out.m10 = a02 * s + a22 * c;
- out.m11 = a03 * s + a23 * c;
-
- return out;
-};
-
-/**
- * Rotates a matrix by the given angle around the Z axis
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat4} out
- */
-mat4.rotateZ = function (out, a, rad) {
- var s = Math.sin(rad),
- c = Math.cos(rad),
- a00 = a.m00,
- a01 = a.m01,
- a02 = a.m02,
- a03 = a.m03,
- a10 = a.m04,
- a11 = a.m05,
- a12 = a.m06,
- a13 = a.m07;
-
- // If the source and destination differ, copy the unchanged last row
- if (a !== out) {
- out.m08 = a.m08;
- out.m09 = a.m09;
- out.m10 = a.m10;
- out.m11 = a.m11;
- out.m12 = a.m12;
- out.m13 = a.m13;
- out.m14 = a.m14;
- out.m15 = a.m15;
- }
-
- // Perform axis-specific matrix multiplication
- out.m00 = a00 * c + a10 * s;
- out.m01 = a01 * c + a11 * s;
- out.m02 = a02 * c + a12 * s;
- out.m03 = a03 * c + a13 * s;
- out.m04 = a10 * c - a00 * s;
- out.m05 = a11 * c - a01 * s;
- out.m06 = a12 * c - a02 * s;
- out.m07 = a13 * c - a03 * s;
-
- return out;
-};
-
-/**
- * Creates a matrix from a vector translation
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.translate(dest, dest, vec);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {vec3} v Translation vector
- * @returns {mat4} out
- */
-mat4.fromTranslation = function (out, v) {
- out.m00 = 1;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 0;
- out.m05 = 1;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 0;
- out.m09 = 0;
- out.m10 = 1;
- out.m11 = 0;
- out.m12 = v.x;
- out.m13 = v.y;
- out.m14 = v.z;
- out.m15 = 1;
- return out;
-};
-
-/**
- * Creates a matrix from a vector scaling
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.scale(dest, dest, vec);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {vec3} v Scaling vector
- * @returns {mat4} out
- */
-mat4.fromScaling = function (out, v) {
- out.m00 = v.x;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 0;
- out.m05 = v.y;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 0;
- out.m09 = 0;
- out.m10 = v.z;
- out.m11 = 0;
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = 0;
- out.m15 = 1;
- return out;
-};
-
-/**
- * Creates a matrix from a given angle around a given axis
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.rotate(dest, dest, rad, axis);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {Number} rad the angle to rotate the matrix by
- * @param {vec3} axis the axis to rotate around
- * @returns {mat4} out
- */
-mat4.fromRotation = function (out, rad, axis) {
- var x = axis.x, y = axis.y, z = axis.z;
- var len = Math.sqrt(x * x + y * y + z * z);
- var s, c, t;
-
- if (Math.abs(len) < EPSILON) {
- return null;
- }
-
- len = 1 / len;
- x *= len;
- y *= len;
- z *= len;
-
- s = Math.sin(rad);
- c = Math.cos(rad);
- t = 1 - c;
-
- // Perform rotation-specific matrix multiplication
- out.m00 = x * x * t + c;
- out.m01 = y * x * t + z * s;
- out.m02 = z * x * t - y * s;
- out.m03 = 0;
- out.m04 = x * y * t - z * s;
- out.m05 = y * y * t + c;
- out.m06 = z * y * t + x * s;
- out.m07 = 0;
- out.m08 = x * z * t + y * s;
- out.m09 = y * z * t - x * s;
- out.m10 = z * z * t + c;
- out.m11 = 0;
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = 0;
- out.m15 = 1;
- return out;
-};
-
-/**
- * Creates a matrix from the given angle around the X axis
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.rotateX(dest, dest, rad);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat4} out
- */
-mat4.fromXRotation = function (out, rad) {
- var s = Math.sin(rad),
- c = Math.cos(rad);
-
- // Perform axis-specific matrix multiplication
- out.m00 = 1;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 0;
- out.m05 = c;
- out.m06 = s;
- out.m07 = 0;
- out.m08 = 0;
- out.m09 = -s;
- out.m10 = c;
- out.m11 = 0;
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = 0;
- out.m15 = 1;
- return out;
-};
-
-/**
- * Creates a matrix from the given angle around the Y axis
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.rotateY(dest, dest, rad);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat4} out
- */
-mat4.fromYRotation = function (out, rad) {
- var s = Math.sin(rad),
- c = Math.cos(rad);
-
- // Perform axis-specific matrix multiplication
- out.m00 = c;
- out.m01 = 0;
- out.m02 = -s;
- out.m03 = 0;
- out.m04 = 0;
- out.m05 = 1;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = s;
- out.m09 = 0;
- out.m10 = c;
- out.m11 = 0;
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = 0;
- out.m15 = 1;
- return out;
-};
-
-/**
- * Creates a matrix from the given angle around the Z axis
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.rotateZ(dest, dest, rad);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat4} out
- */
-mat4.fromZRotation = function (out, rad) {
- var s = Math.sin(rad),
- c = Math.cos(rad);
-
- // Perform axis-specific matrix multiplication
- out.m00 = c;
- out.m01 = s;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = -s;
- out.m05 = c;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 0;
- out.m09 = 0;
- out.m10 = 1;
- out.m11 = 0;
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = 0;
- out.m15 = 1;
- return out;
-};
-
-/**
- * Creates a matrix from a quaternion rotation and vector translation
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.translate(dest, vec);
- * let quatMat = mat4.create();
- * quat.toMat4(quat, quatMat);
- * mat4.multiply(dest, quatMat);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {quat} q Rotation quaternion
- * @param {vec3} v Translation vector
- * @returns {mat4} out
- */
-mat4.fromRT = function (out, q, v) {
- // Quaternion math
- var x = q.x, y = q.y, z = q.z, w = q.w;
- var x2 = x + x;
- var y2 = y + y;
- var z2 = z + z;
-
- var xx = x * x2;
- var xy = x * y2;
- var xz = x * z2;
- var yy = y * y2;
- var yz = y * z2;
- var zz = z * z2;
- var wx = w * x2;
- var wy = w * y2;
- var wz = w * z2;
-
- out.m00 = 1 - (yy + zz);
- out.m01 = xy + wz;
- out.m02 = xz - wy;
- out.m03 = 0;
- out.m04 = xy - wz;
- out.m05 = 1 - (xx + zz);
- out.m06 = yz + wx;
- out.m07 = 0;
- out.m08 = xz + wy;
- out.m09 = yz - wx;
- out.m10 = 1 - (xx + yy);
- out.m11 = 0;
- out.m12 = v.x;
- out.m13 = v.y;
- out.m14 = v.z;
- out.m15 = 1;
-
- return out;
-};
-
-/**
- * Returns the translation vector component of a transformation
- * matrix. If a matrix is built with fromRT,
- * the returned vector will be the same as the translation vector
- * originally supplied.
- * @param {vec3} out Vector to receive translation component
- * @param {mat4} mat Matrix to be decomposed (input)
- * @return {vec3} out
- */
-mat4.getTranslation = function (out, mat) {
- out.x = mat.m12;
- out.y = mat.m13;
- out.z = mat.m14;
-
- return out;
-};
-
-/**
- * Returns the scaling factor component of a transformation
- * matrix. If a matrix is built with fromRTS
- * with a normalized Quaternion paramter, the returned vector will be
- * the same as the scaling vector
- * originally supplied.
- * @param {vec3} out Vector to receive scaling factor component
- * @param {mat4} mat Matrix to be decomposed (input)
- * @return {vec3} out
- */
-mat4.getScaling = function (out, mat) {
- var m11 = mat.m00,
- m12 = mat.m01,
- m13 = mat.m02,
- m21 = mat.m04,
- m22 = mat.m05,
- m23 = mat.m06,
- m31 = mat.m08,
- m32 = mat.m09,
- m33 = mat.m10;
-
- out.x = Math.sqrt(m11 * m11 + m12 * m12 + m13 * m13);
- out.y = Math.sqrt(m21 * m21 + m22 * m22 + m23 * m23);
- out.z = Math.sqrt(m31 * m31 + m32 * m32 + m33 * m33);
-
- return out;
-};
-
-/**
- * Returns a quaternion representing the rotational component
- * of a transformation matrix. If a matrix is built with
- * fromRT, the returned quaternion will be the
- * same as the quaternion originally supplied.
- * @param {quat} out Quaternion to receive the rotation component
- * @param {mat4} mat Matrix to be decomposed (input)
- * @return {quat} out
- */
-mat4.getRotation = function (out, mat) {
- // Algorithm taken from http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
- var trace = mat.m00 + mat.m05 + mat.m10;
- var S = 0;
-
- if (trace > 0) {
- S = Math.sqrt(trace + 1.0) * 2;
- out.w = 0.25 * S;
- out.x = (mat.m06 - mat.m09) / S;
- out.y = (mat.m08 - mat.m02) / S;
- out.z = (mat.m01 - mat.m04) / S;
- } else if ((mat.m00 > mat.m05) & (mat.m00 > mat.m10)) {
- S = Math.sqrt(1.0 + mat.m00 - mat.m05 - mat.m10) * 2;
- out.w = (mat.m06 - mat.m09) / S;
- out.x = 0.25 * S;
- out.y = (mat.m01 + mat.m04) / S;
- out.z = (mat.m08 + mat.m02) / S;
- } else if (mat.m05 > mat.m10) {
- S = Math.sqrt(1.0 + mat.m05 - mat.m00 - mat.m10) * 2;
- out.w = (mat.m08 - mat.m02) / S;
- out.x = (mat.m01 + mat.m04) / S;
- out.y = 0.25 * S;
- out.z = (mat.m06 + mat.m09) / S;
- } else {
- S = Math.sqrt(1.0 + mat.m10 - mat.m00 - mat.m05) * 2;
- out.w = (mat.m01 - mat.m04) / S;
- out.x = (mat.m08 + mat.m02) / S;
- out.y = (mat.m06 + mat.m09) / S;
- out.z = 0.25 * S;
- }
-
- return out;
-};
-
-/**
- * Creates a matrix from a quaternion rotation, vector translation and vector scale
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.translate(dest, vec);
- * let quatMat = mat4.create();
- * quat.toMat4(quat, quatMat);
- * mat4.multiply(dest, quatMat);
- * mat4.scale(dest, scale)
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {quat} q Rotation quaternion
- * @param {vec3} v Translation vector
- * @param {vec3} s Scaling vector
- * @returns {mat4} out
- */
-mat4.fromRTS = function (out, q, v, s) {
- // Quaternion math
- var x = q.x, y = q.y, z = q.z, w = q.w;
- var x2 = x + x;
- var y2 = y + y;
- var z2 = z + z;
-
- var xx = x * x2;
- var xy = x * y2;
- var xz = x * z2;
- var yy = y * y2;
- var yz = y * z2;
- var zz = z * z2;
- var wx = w * x2;
- var wy = w * y2;
- var wz = w * z2;
- var sx = s.x;
- var sy = s.y;
- var sz = s.z;
-
- out.m00 = (1 - (yy + zz)) * sx;
- out.m01 = (xy + wz) * sx;
- out.m02 = (xz - wy) * sx;
- out.m03 = 0;
- out.m04 = (xy - wz) * sy;
- out.m05 = (1 - (xx + zz)) * sy;
- out.m06 = (yz + wx) * sy;
- out.m07 = 0;
- out.m08 = (xz + wy) * sz;
- out.m09 = (yz - wx) * sz;
- out.m10 = (1 - (xx + yy)) * sz;
- out.m11 = 0;
- out.m12 = v.x;
- out.m13 = v.y;
- out.m14 = v.z;
- out.m15 = 1;
-
- return out;
-};
-
-/**
- * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.translate(dest, vec);
- * mat4.translate(dest, origin);
- * let quatMat = mat4.create();
- * quat.toMat4(quat, quatMat);
- * mat4.multiply(dest, quatMat);
- * mat4.scale(dest, scale)
- * mat4.translate(dest, negativeOrigin);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {quat} q Rotation quaternion
- * @param {vec3} v Translation vector
- * @param {vec3} s Scaling vector
- * @param {vec3} o The origin vector around which to scale and rotate
- * @returns {mat4} out
- */
-mat4.fromRTSOrigin = function (out, q, v, s, o) {
- // Quaternion math
- var x = q.x, y = q.y, z = q.z, w = q.w;
- var x2 = x + x;
- var y2 = y + y;
- var z2 = z + z;
-
- var xx = x * x2;
- var xy = x * y2;
- var xz = x * z2;
- var yy = y * y2;
- var yz = y * z2;
- var zz = z * z2;
- var wx = w * x2;
- var wy = w * y2;
- var wz = w * z2;
-
- var sx = s.x;
- var sy = s.y;
- var sz = s.z;
-
- var ox = o.x;
- var oy = o.y;
- var oz = o.z;
-
- out.m00 = (1 - (yy + zz)) * sx;
- out.m01 = (xy + wz) * sx;
- out.m02 = (xz - wy) * sx;
- out.m03 = 0;
- out.m04 = (xy - wz) * sy;
- out.m05 = (1 - (xx + zz)) * sy;
- out.m06 = (yz + wx) * sy;
- out.m07 = 0;
- out.m08 = (xz + wy) * sz;
- out.m09 = (yz - wx) * sz;
- out.m10 = (1 - (xx + yy)) * sz;
- out.m11 = 0;
- out.m12 = v.x + ox - (out.m00 * ox + out.m04 * oy + out.m08 * oz);
- out.m13 = v.y + oy - (out.m01 * ox + out.m05 * oy + out.m09 * oz);
- out.m14 = v.z + oz - (out.m02 * ox + out.m06 * oy + out.m10 * oz);
- out.m15 = 1;
-
- return out;
-};
-
-/**
- * Calculates a 4x4 matrix from the given quaternion
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {quat} q Quaternion to create matrix from
- *
- * @returns {mat4} out
- */
-mat4.fromQuat = function (out, q) {
- var x = q.x, y = q.y, z = q.z, w = q.w;
- var x2 = x + x;
- var y2 = y + y;
- var z2 = z + z;
-
- var xx = x * x2;
- var yx = y * x2;
- var yy = y * y2;
- var zx = z * x2;
- var zy = z * y2;
- var zz = z * z2;
- var wx = w * x2;
- var wy = w * y2;
- var wz = w * z2;
-
- out.m00 = 1 - yy - zz;
- out.m01 = yx + wz;
- out.m02 = zx - wy;
- out.m03 = 0;
-
- out.m04 = yx - wz;
- out.m05 = 1 - xx - zz;
- out.m06 = zy + wx;
- out.m07 = 0;
-
- out.m08 = zx + wy;
- out.m09 = zy - wx;
- out.m10 = 1 - xx - yy;
- out.m11 = 0;
-
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = 0;
- out.m15 = 1;
-
- return out;
-};
-
-/**
- * Generates a frustum matrix with the given bounds
- *
- * @param {mat4} out mat4 frustum matrix will be written into
- * @param {Number} left Left bound of the frustum
- * @param {Number} right Right bound of the frustum
- * @param {Number} bottom Bottom bound of the frustum
- * @param {Number} top Top bound of the frustum
- * @param {Number} near Near bound of the frustum
- * @param {Number} far Far bound of the frustum
- * @returns {mat4} out
- */
-mat4.frustum = function (out, left, right, bottom, top, near, far) {
- var rl = 1 / (right - left);
- var tb = 1 / (top - bottom);
- var nf = 1 / (near - far);
-
- out.m00 = (near * 2) * rl;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 0;
- out.m05 = (near * 2) * tb;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = (right + left) * rl;
- out.m09 = (top + bottom) * tb;
- out.m10 = (far + near) * nf;
- out.m11 = -1;
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = (far * near * 2) * nf;
- out.m15 = 0;
- return out;
-};
-
-/**
- * Generates a perspective projection matrix with the given bounds
- *
- * @param {mat4} out mat4 frustum matrix will be written into
- * @param {number} fovy Vertical field of view in radians
- * @param {number} aspect Aspect ratio. typically viewport width/height
- * @param {number} near Near bound of the frustum
- * @param {number} far Far bound of the frustum
- * @returns {mat4} out
- */
-mat4.perspective = function (out, fovy, aspect, near, far) {
- var f = 1.0 / Math.tan(fovy / 2);
- var nf = 1 / (near - far);
-
- out.m00 = f / aspect;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 0;
- out.m05 = f;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 0;
- out.m09 = 0;
- out.m10 = (far + near) * nf;
- out.m11 = -1;
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = (2 * far * near) * nf;
- out.m15 = 0;
- return out;
-};
-
-/**
- * Generates a perspective projection matrix with the given field of view.
- * This is primarily useful for generating projection matrices to be used
- * with the still experiemental WebVR API.
- *
- * @param {mat4} out mat4 frustum matrix will be written into
- * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees
- * @param {number} near Near bound of the frustum
- * @param {number} far Far bound of the frustum
- * @returns {mat4} out
- */
-mat4.perspectiveFromFieldOfView = function (out, fov, near, far) {
- var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0);
- var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0);
- var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0);
- var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0);
- var xScale = 2.0 / (leftTan + rightTan);
- var yScale = 2.0 / (upTan + downTan);
-
- out.m00 = xScale;
- out.m01 = 0.0;
- out.m02 = 0.0;
- out.m03 = 0.0;
- out.m04 = 0.0;
- out.m05 = yScale;
- out.m06 = 0.0;
- out.m07 = 0.0;
- out.m08 = -((leftTan - rightTan) * xScale * 0.5);
- out.m09 = ((upTan - downTan) * yScale * 0.5);
- out.m10 = far / (near - far);
- out.m11 = -1.0;
- out.m12 = 0.0;
- out.m13 = 0.0;
- out.m14 = (far * near) / (near - far);
- out.m15 = 0.0;
- return out;
-};
-
-/**
- * Generates a orthogonal projection matrix with the given bounds
- *
- * @param {mat4} out mat4 frustum matrix will be written into
- * @param {number} left Left bound of the frustum
- * @param {number} right Right bound of the frustum
- * @param {number} bottom Bottom bound of the frustum
- * @param {number} top Top bound of the frustum
- * @param {number} near Near bound of the frustum
- * @param {number} far Far bound of the frustum
- * @returns {mat4} out
- */
-mat4.ortho = function (out, left, right, bottom, top, near, far) {
- var lr = 1 / (left - right);
- var bt = 1 / (bottom - top);
- var nf = 1 / (near - far);
- out.m00 = -2 * lr;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 0;
- out.m05 = -2 * bt;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 0;
- out.m09 = 0;
- out.m10 = 2 * nf;
- out.m11 = 0;
- out.m12 = (left + right) * lr;
- out.m13 = (top + bottom) * bt;
- out.m14 = (far + near) * nf;
- out.m15 = 1;
- return out;
-};
-
-/**
- * Generates a look-at matrix with the given eye position, focal point, and up axis
- *
- * @param {mat4} out mat4 frustum matrix will be written into
- * @param {vec3} eye Position of the viewer
- * @param {vec3} center Point the viewer is looking at
- * @param {vec3} up vec3 pointing up
- * @returns {mat4} out
- */
-mat4.lookAt = function (out, eye, center, up) {
- var x0, x1, x2, y0, y1, y2, z0, z1, z2, len;
- var eyex = eye.x;
- var eyey = eye.y;
- var eyez = eye.z;
- var upx = up.x;
- var upy = up.y;
- var upz = up.z;
- var centerx = center.x;
- var centery = center.y;
- var centerz = center.z;
-
- if (
- Math.abs(eyex - centerx) < EPSILON &&
- Math.abs(eyey - centery) < EPSILON &&
- Math.abs(eyez - centerz) < EPSILON
- ) {
- return mat4.identity(out);
- }
-
- z0 = eyex - centerx;
- z1 = eyey - centery;
- z2 = eyez - centerz;
-
- len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
- z0 *= len;
- z1 *= len;
- z2 *= len;
-
- x0 = upy * z2 - upz * z1;
- x1 = upz * z0 - upx * z2;
- x2 = upx * z1 - upy * z0;
- len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
- if (!len) {
- x0 = 0;
- x1 = 0;
- x2 = 0;
- } else {
- len = 1 / len;
- x0 *= len;
- x1 *= len;
- x2 *= len;
- }
-
- y0 = z1 * x2 - z2 * x1;
- y1 = z2 * x0 - z0 * x2;
- y2 = z0 * x1 - z1 * x0;
-
- len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
- if (!len) {
- y0 = 0;
- y1 = 0;
- y2 = 0;
- } else {
- len = 1 / len;
- y0 *= len;
- y1 *= len;
- y2 *= len;
- }
-
- out.m00 = x0;
- out.m01 = y0;
- out.m02 = z0;
- out.m03 = 0;
- out.m04 = x1;
- out.m05 = y1;
- out.m06 = z1;
- out.m07 = 0;
- out.m08 = x2;
- out.m09 = y2;
- out.m10 = z2;
- out.m11 = 0;
- out.m12 = -(x0 * eyex + x1 * eyey + x2 * eyez);
- out.m13 = -(y0 * eyex + y1 * eyey + y2 * eyez);
- out.m14 = -(z0 * eyex + z1 * eyey + z2 * eyez);
- out.m15 = 1;
-
- return out;
-};
-
-/**
- * Returns a string representation of a mat4
- *
- * @param {mat4} a matrix to represent as a string
- * @returns {String} string representation of the matrix
- */
-mat4.str = function (a) {
- return ("mat4(" + (a.m00) + ", " + (a.m01) + ", " + (a.m02) + ", " + (a.m03) + ", " + (a.m04) + ", " + (a.m05) + ", " + (a.m06) + ", " + (a.m07) + ", " + (a.m08) + ", " + (a.m09) + ", " + (a.m10) + ", " + (a.m11) + ", " + (a.m12) + ", " + (a.m13) + ", " + (a.m14) + ", " + (a.m15) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {mat4} m
- * @returns {array}
- */
-mat4.array = function (out, m) {
- out[0] = m.m00;
- out[1] = m.m01;
- out[2] = m.m02;
- out[3] = m.m03;
- out[4] = m.m04;
- out[5] = m.m05;
- out[6] = m.m06;
- out[7] = m.m07;
- out[8] = m.m08;
- out[9] = m.m09;
- out[10] = m.m10;
- out[11] = m.m11;
- out[12] = m.m12;
- out[13] = m.m13;
- out[14] = m.m14;
- out[15] = m.m15;
-
- return out;
-};
-
-/**
- * Returns Frobenius norm of a mat4
- *
- * @param {mat4} a the matrix to calculate Frobenius norm of
- * @returns {Number} Frobenius norm
- */
-mat4.frob = function (a) {
- return (Math.sqrt(Math.pow(a.m00, 2) + Math.pow(a.m01, 2) + Math.pow(a.m02, 2) + Math.pow(a.m03, 2) + Math.pow(a.m04, 2) + Math.pow(a.m05, 2) + Math.pow(a.m06, 2) + Math.pow(a.m07, 2) + Math.pow(a.m08, 2) + Math.pow(a.m09, 2) + Math.pow(a.m10, 2) + Math.pow(a.m11, 2) + Math.pow(a.m12, 2) + Math.pow(a.m13, 2) + Math.pow(a.m14, 2) + Math.pow(a.m15, 2)))
-};
-
-/**
- * Adds two mat4's
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the first operand
- * @param {mat4} b the second operand
- * @returns {mat4} out
- */
-mat4.add = function (out, a, b) {
- out.m00 = a.m00 + b.m00;
- out.m01 = a.m01 + b.m01;
- out.m02 = a.m02 + b.m02;
- out.m03 = a.m03 + b.m03;
- out.m04 = a.m04 + b.m04;
- out.m05 = a.m05 + b.m05;
- out.m06 = a.m06 + b.m06;
- out.m07 = a.m07 + b.m07;
- out.m08 = a.m08 + b.m08;
- out.m09 = a.m09 + b.m09;
- out.m10 = a.m10 + b.m10;
- out.m11 = a.m11 + b.m11;
- out.m12 = a.m12 + b.m12;
- out.m13 = a.m13 + b.m13;
- out.m14 = a.m14 + b.m14;
- out.m15 = a.m15 + b.m15;
- return out;
-};
-
-/**
- * Subtracts matrix b from matrix a
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the first operand
- * @param {mat4} b the second operand
- * @returns {mat4} out
- */
-mat4.subtract = function (out, a, b) {
- out.m00 = a.m00 - b.m00;
- out.m01 = a.m01 - b.m01;
- out.m02 = a.m02 - b.m02;
- out.m03 = a.m03 - b.m03;
- out.m04 = a.m04 - b.m04;
- out.m05 = a.m05 - b.m05;
- out.m06 = a.m06 - b.m06;
- out.m07 = a.m07 - b.m07;
- out.m08 = a.m08 - b.m08;
- out.m09 = a.m09 - b.m09;
- out.m10 = a.m10 - b.m10;
- out.m11 = a.m11 - b.m11;
- out.m12 = a.m12 - b.m12;
- out.m13 = a.m13 - b.m13;
- out.m14 = a.m14 - b.m14;
- out.m15 = a.m15 - b.m15;
- return out;
-};
-
-/**
- * Alias for {@link mat4.subtract}
- * @function
- */
-mat4.sub = mat4.subtract;
-
-/**
- * Multiply each element of the matrix by a scalar.
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the matrix to scale
- * @param {Number} b amount to scale the matrix's elements by
- * @returns {mat4} out
- */
-mat4.multiplyScalar = function (out, a, b) {
- out.m00 = a.m00 * b;
- out.m01 = a.m01 * b;
- out.m02 = a.m02 * b;
- out.m03 = a.m03 * b;
- out.m04 = a.m04 * b;
- out.m05 = a.m05 * b;
- out.m06 = a.m06 * b;
- out.m07 = a.m07 * b;
- out.m08 = a.m08 * b;
- out.m09 = a.m09 * b;
- out.m10 = a.m10 * b;
- out.m11 = a.m11 * b;
- out.m12 = a.m12 * b;
- out.m13 = a.m13 * b;
- out.m14 = a.m14 * b;
- out.m15 = a.m15 * b;
- return out;
-};
-
-/**
- * Adds two mat4's after multiplying each element of the second operand by a scalar value.
- *
- * @param {mat4} out the receiving vector
- * @param {mat4} a the first operand
- * @param {mat4} b the second operand
- * @param {Number} scale the amount to scale b's elements by before adding
- * @returns {mat4} out
- */
-mat4.multiplyScalarAndAdd = function (out, a, b, scale) {
- out.m00 = a.m00 + (b.m00 * scale);
- out.m01 = a.m01 + (b.m01 * scale);
- out.m02 = a.m02 + (b.m02 * scale);
- out.m03 = a.m03 + (b.m03 * scale);
- out.m04 = a.m04 + (b.m04 * scale);
- out.m05 = a.m05 + (b.m05 * scale);
- out.m06 = a.m06 + (b.m06 * scale);
- out.m07 = a.m07 + (b.m07 * scale);
- out.m08 = a.m08 + (b.m08 * scale);
- out.m09 = a.m09 + (b.m09 * scale);
- out.m10 = a.m10 + (b.m10 * scale);
- out.m11 = a.m11 + (b.m11 * scale);
- out.m12 = a.m12 + (b.m12 * scale);
- out.m13 = a.m13 + (b.m13 * scale);
- out.m14 = a.m14 + (b.m14 * scale);
- out.m15 = a.m15 + (b.m15 * scale);
- return out;
-};
-
-/**
- * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
- *
- * @param {mat4} a The first matrix.
- * @param {mat4} b The second matrix.
- * @returns {Boolean} True if the matrices are equal, false otherwise.
- */
-mat4.exactEquals = function (a, b) {
- return a.m00 === b.m00 && a.m01 === b.m01 && a.m02 === b.m02 && a.m03 === b.m03 &&
- a.m04 === b.m04 && a.m05 === b.m05 && a.m06 === b.m06 && a.m07 === b.m07 &&
- a.m08 === b.m08 && a.m09 === b.m09 && a.m10 === b.m10 && a.m11 === b.m11 &&
- a.m12 === b.m12 && a.m13 === b.m13 && a.m14 === b.m14 && a.m15 === b.m15;
-};
-
-/**
- * Returns whether or not the matrices have approximately the same elements in the same position.
- *
- * @param {mat4} a The first matrix.
- * @param {mat4} b The second matrix.
- * @returns {Boolean} True if the matrices are equal, false otherwise.
- */
-mat4.equals = function (a, b) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03,
- a4 = a.m04, a5 = a.m05, a6 = a.m06, a7 = a.m07,
- a8 = a.m08, a9 = a.m09, a10 = a.m10, a11 = a.m11,
- a12 = a.m12, a13 = a.m13, a14 = a.m14, a15 = a.m15;
-
- var b0 = b.m00, b1 = b.m01, b2 = b.m02, b3 = b.m03,
- b4 = b.m04, b5 = b.m05, b6 = b.m06, b7 = b.m07,
- b8 = b.m08, b9 = b.m09, b10 = b.m10, b11 = b.m11,
- b12 = b.m12, b13 = b.m13, b14 = b.m14, b15 = b.m15;
-
- return (
- Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
- Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
- Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&
- Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&
- Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&
- Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&
- Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) &&
- Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8)) &&
- Math.abs(a9 - b9) <= EPSILON * Math.max(1.0, Math.abs(a9), Math.abs(b9)) &&
- Math.abs(a10 - b10) <= EPSILON * Math.max(1.0, Math.abs(a10), Math.abs(b10)) &&
- Math.abs(a11 - b11) <= EPSILON * Math.max(1.0, Math.abs(a11), Math.abs(b11)) &&
- Math.abs(a12 - b12) <= EPSILON * Math.max(1.0, Math.abs(a12), Math.abs(b12)) &&
- Math.abs(a13 - b13) <= EPSILON * Math.max(1.0, Math.abs(a13), Math.abs(b13)) &&
- Math.abs(a14 - b14) <= EPSILON * Math.max(1.0, Math.abs(a14), Math.abs(b14)) &&
- Math.abs(a15 - b15) <= EPSILON * Math.max(1.0, Math.abs(a15), Math.abs(b15))
- );
-};
-
-var _tmp$8 = new Array(3);
-
-var _color3 = function _color3(r, g, b) {
- this.r = r;
- this.g = g;
- this.b = b;
-};
-
-_color3.prototype.toJSON = function toJSON () {
- _tmp$8[0] = this.r;
- _tmp$8[1] = this.g;
- _tmp$8[2] = this.b;
-
- return _tmp$8;
-};
-
-/**
- * @class Color
- * @name color3
- */
-var color3 = {};
-
-/**
- * Creates a new color
- *
- * @returns {color3} a new color
- */
-color3.create = function () {
- return new _color3(1, 1, 1);
-};
-
-/**
- * Creates a new color initialized with the given values
- *
- * @param {Number} r red component
- * @param {Number} g green component
- * @param {Number} b blue component
- * @returns {color3} a new color
- * @function
- */
-color3.new = function (r, g, b) {
- return new _color3(r, g, b);
-};
-
-/**
- * Creates a new color initialized with values from an existing quaternion
- *
- * @param {color3} a color to clone
- * @returns {color3} a new color
- * @function
- */
-color3.clone = function (a) {
- return new _color3(a.r, a.g, a.b, a.a);
-};
-
-/**
- * Copy the values from one color to another
- *
- * @param {color3} out the receiving color
- * @param {color3} a the source color
- * @returns {color3} out
- * @function
- */
-color3.copy = function (out, a) {
- out.r = a.r;
- out.g = a.g;
- out.b = a.b;
- return out;
-};
-
-/**
- * Set the components of a color to the given values
- *
- * @param {color3} out the receiving color
- * @param {Number} r red component
- * @param {Number} g green component
- * @param {Number} b blue component
- * @returns {color3} out
- * @function
- */
-color3.set = function (out, r, g, b) {
- out.r = r;
- out.g = g;
- out.b = b;
- return out;
-};
-
-/**
- * Set from hex
- *
- * @param {color3} out the receiving color
- * @param {Number} hex
- * @returns {color3} out
- * @function
- */
-color3.fromHex = function (out, hex) {
- var r = ((hex >> 16)) / 255.0;
- var g = ((hex >> 8) & 0xff) / 255.0;
- var b = ((hex) & 0xff) / 255.0;
-
- out.r = r;
- out.g = g;
- out.b = b;
- return out;
-};
-
-/**
- * Adds two color's
- *
- * @param {color3} out the receiving color
- * @param {color3} a the first operand
- * @param {color3} b the second operand
- * @returns {color3} out
- * @function
- */
-color3.add = function (out, a, b) {
- out.r = a.r + b.r;
- out.g = a.g + b.g;
- out.b = a.b + b.b;
- return out;
-};
-
-/**
- * Subtracts color b from color a
- *
- * @param {color3} out the receiving color
- * @param {color3} a the first operand
- * @param {color3} b the second operand
- * @returns {color3} out
- */
-color3.subtract = function (out, a, b) {
- out.r = a.r - b.r;
- out.g = a.g - b.g;
- out.b = a.b - b.b;
- return out;
-};
-
-/**
- * Alias for {@link color3.subtract}
- * @function
- */
-color3.sub = color3.subtract;
-
-/**
- * Multiplies two color's
- *
- * @param {color3} out the receiving color
- * @param {color3} a the first operand
- * @param {color3} b the second operand
- * @returns {color3} out
- * @function
- */
-color3.multiply = function (out, a, b) {
- out.r = a.r * b.r;
- out.g = a.g * b.g;
- out.b = a.b * b.b;
- return out;
-};
-
-/**
- * Alias for {@link color3.multiply}
- * @function
- */
-color3.mul = color3.multiply;
-
-/**
- * Divides two color's
- *
- * @param {color3} out the receiving vector
- * @param {color3} a the first operand
- * @param {color3} b the second operand
- * @returns {color3} out
- */
-color3.divide = function (out, a, b) {
- out.r = a.r / b.r;
- out.g = a.g / b.g;
- out.b = a.b / b.b;
- return out;
-};
-
-/**
- * Alias for {@link color3.divide}
- * @function
- */
-color3.div = color3.divide;
-
-
-/**
- * Scales a color by a scalar number
- *
- * @param {color3} out the receiving vector
- * @param {color3} a the vector to scale
- * @param {Number} b amount to scale the vector by
- * @returns {color3} out
- * @function
- */
-color3.scale = function (out, a, b) {
- out.r = a.r * b;
- out.g = a.g * b;
- out.b = a.b * b;
- return out;
-};
-
-/**
- * Performs a linear interpolation between two color's
- *
- * @param {color3} out the receiving color
- * @param {color3} a the first operand
- * @param {color3} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {color3} out
- * @function
- */
-color3.lerp = function (out, a, b, t) {
- var ar = a.r,
- ag = a.g,
- ab = a.b;
- out.r = ar + t * (b.r - ar);
- out.g = ag + t * (b.g - ag);
- out.b = ab + t * (b.b - ab);
- return out;
-};
-
-/**
- * Returns a string representation of a color
- *
- * @param {color3} a vector to represent as a string
- * @returns {String} string representation of the vector
- */
-color3.str = function (a) {
- return ("color3(" + (a.r) + ", " + (a.g) + ", " + (a.b) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {color3} a
- * @returns {array}
- */
-color3.array = function (out, a) {
- out[0] = a.r;
- out[1] = a.g;
- out[2] = a.b;
-
- return out;
-};
-
-/**
- * Returns whether or not the color have exactly the same elements in the same position (when compared with ===)
- *
- * @param {color3} a The first color3.
- * @param {color3} b The second color3.
- * @returns {Boolean} True if the colors are equal, false otherwise.
- */
-color3.exactEquals = function (a, b) {
- return a.r === b.r && a.g === b.g && a.b === b.b;
-};
-
-/**
- * Returns whether or not the colors have approximately the same elements in the same position.
- *
- * @param {color3} a The first color3.
- * @param {color3} b The second color3.
- * @returns {Boolean} True if the colors are equal, false otherwise.
- */
-color3.equals = function (a, b) {
- var a0 = a.r, a1 = a.g, a2 = a.b;
- var b0 = b.r, b1 = b.g, b2 = b.b;
- return (Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
- Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)));
-};
-
-/**
- * Returns the hex value
- *
- * @param {color3} a The color
- * @returns {Number}
- */
-color3.hex = function (a) {
- return (a.r * 255) << 16 | (a.g * 255) << 8 | (a.b * 255);
-};
-
-var _tmp$9 = new Array(4);
-
-var _color4 = function _color4(r, g, b, a) {
- this.r = r;
- this.g = g;
- this.b = b;
- this.a = a;
-};
-
-_color4.prototype.toJSON = function toJSON () {
- _tmp$9[0] = this.r;
- _tmp$9[1] = this.g;
- _tmp$9[2] = this.b;
- _tmp$9[3] = this.a;
-
- return _tmp$9;
-};
-
-/**
- * @class Color
- * @name color4
- */
-var color4 = {};
-
-/**
- * Creates a new color
- *
- * @returns {color4} a new color
- */
-color4.create = function () {
- return new _color4(1, 1, 1, 1);
-};
-
-/**
- * Creates a new color initialized with the given values
- *
- * @param {Number} r red component
- * @param {Number} g green component
- * @param {Number} b blue component
- * @param {Number} a alpha component
- * @returns {color4} a new color
- * @function
- */
-color4.new = function (r, g, b, a) {
- return new _color4(r, g, b, a);
-};
-
-/**
- * Creates a new color initialized with values from an existing quaternion
- *
- * @param {color4} a color to clone
- * @returns {color4} a new color
- * @function
- */
-color4.clone = function (a) {
- return new _color4(a.r, a.g, a.b, a.a);
-};
-
-/**
- * Copy the values from one color to another
- *
- * @param {color4} out the receiving color
- * @param {color4} a the source color
- * @returns {color4} out
- * @function
- */
-color4.copy = function (out, a) {
- out.r = a.r;
- out.g = a.g;
- out.b = a.b;
- out.a = a.a;
- return out;
-};
-
-/**
- * Set the components of a color to the given values
- *
- * @param {color4} out the receiving color
- * @param {Number} r red component
- * @param {Number} g green component
- * @param {Number} b blue component
- * @param {Number} a alpha component
- * @returns {color4} out
- * @function
- */
-color4.set = function (out, r, g, b, a) {
- out.r = r;
- out.g = g;
- out.b = b;
- out.a = a;
- return out;
-};
-
-/**
- * Set from hex
- *
- * @param {color4} out the receiving color
- * @param {Number} hex
- * @returns {color4} out
- * @function
- */
-color4.fromHex = function (out, hex) {
- var r = ((hex >> 24)) / 255.0;
- var g = ((hex >> 16) & 0xff) / 255.0;
- var b = ((hex >> 8) & 0xff) / 255.0;
- var a = ((hex) & 0xff) / 255.0;
-
- out.r = r;
- out.g = g;
- out.b = b;
- out.a = a;
- return out;
-};
-
-/**
- * Adds two color's
- *
- * @param {color4} out the receiving color
- * @param {color4} a the first operand
- * @param {color4} b the second operand
- * @returns {color4} out
- * @function
- */
-color4.add = function (out, a, b) {
- out.r = a.r + b.r;
- out.g = a.g + b.g;
- out.b = a.b + b.b;
- out.a = a.a + b.a;
- return out;
-};
-
-/**
- * Subtracts color b from color a
- *
- * @param {color4} out the receiving color
- * @param {color4} a the first operand
- * @param {color4} b the second operand
- * @returns {color4} out
- */
-color4.subtract = function (out, a, b) {
- out.r = a.r - b.r;
- out.g = a.g - b.g;
- out.b = a.b - b.b;
- out.a = a.a - b.a;
- return out;
-};
-
-/**
- * Alias for {@link color4.subtract}
- * @function
- */
-color4.sub = color4.subtract;
-
-/**
- * Multiplies two color's
- *
- * @param {color4} out the receiving color
- * @param {color4} a the first operand
- * @param {color4} b the second operand
- * @returns {color4} out
- * @function
- */
-color4.multiply = function (out, a, b) {
- out.r = a.r * b.r;
- out.g = a.g * b.g;
- out.b = a.b * b.b;
- out.a = a.a * b.a;
- return out;
-};
-
-/**
- * Alias for {@link color4.multiply}
- * @function
- */
-color4.mul = color4.multiply;
-
-/**
- * Divides two color's
- *
- * @param {color4} out the receiving vector
- * @param {color4} a the first operand
- * @param {color4} b the second operand
- * @returns {color4} out
- */
-color4.divide = function (out, a, b) {
- out.r = a.r / b.r;
- out.g = a.g / b.g;
- out.b = a.b / b.b;
- out.a = a.a / b.a;
- return out;
-};
-
-/**
- * Alias for {@link color4.divide}
- * @function
- */
-color4.div = color4.divide;
-
-
-/**
- * Scales a color by a scalar number
- *
- * @param {color4} out the receiving vector
- * @param {color4} a the vector to scale
- * @param {Number} b amount to scale the vector by
- * @returns {color4} out
- * @function
- */
-color4.scale = function (out, a, b) {
- out.r = a.r * b;
- out.g = a.g * b;
- out.b = a.b * b;
- out.a = a.a * b;
- return out;
-};
-
-/**
- * Performs a linear interpolation between two color's
- *
- * @param {color4} out the receiving color
- * @param {color4} a the first operand
- * @param {color4} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {color4} out
- * @function
- */
-color4.lerp = function (out, a, b, t) {
- var ar = a.r,
- ag = a.g,
- ab = a.b,
- aa = a.a;
- out.r = ar + t * (b.r - ar);
- out.g = ag + t * (b.g - ag);
- out.b = ab + t * (b.b - ab);
- out.a = aa + t * (b.a - aa);
- return out;
-};
-
-/**
- * Returns a string representation of a color
- *
- * @param {color4} a vector to represent as a string
- * @returns {String} string representation of the vector
- */
-color4.str = function (a) {
- return ("color4(" + (a.r) + ", " + (a.g) + ", " + (a.b) + ", " + (a.a) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {color4} a
- * @returns {array}
- */
-color4.array = function (out, a) {
- out[0] = a.r;
- out[1] = a.g;
- out[2] = a.b;
- out[3] = a.a;
-
- return out;
-};
-
-/**
- * Returns whether or not the color have exactly the same elements in the same position (when compared with ===)
- *
- * @param {color4} a The first color4.
- * @param {color4} b The second color4.
- * @returns {Boolean} True if the colors are equal, false otherwise.
- */
-color4.exactEquals = function (a, b) {
- return a.r === b.r && a.g === b.g && a.b === b.b && a.a === b.a;
-};
-
-/**
- * Returns whether or not the colors have approximately the same elements in the same position.
- *
- * @param {color4} a The first color4.
- * @param {color4} b The second color4.
- * @returns {Boolean} True if the colors are equal, false otherwise.
- */
-color4.equals = function (a, b) {
- var a0 = a.r, a1 = a.g, a2 = a.b, a3 = a.a;
- var b0 = b.r, b1 = b.g, b2 = b.b, b3 = b.a;
- return (Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
- Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
- Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)));
-};
-
-/**
- * Returns the hex value
- *
- * @param {color4} a The color
- * @returns {Number}
- */
-color4.hex = function (a) {
- return ((a.r * 255) << 24 | (a.g * 255) << 16 | (a.b * 255) << 8 | a.a * 255) >>> 0;
-};
-
-// NOTE: there is no syntax for: export {* as bits} from './lib/bits';
-var bits = bits_;
-
-
-
-var math = Object.freeze({
- bits: bits,
- vec2: vec2,
- vec3: vec3,
- vec4: vec4,
- quat: quat,
- mat2: mat2,
- mat23: mat23,
- mat3: mat3,
- mat4: mat4,
- color3: color3,
- color4: color4,
- EPSILON: EPSILON,
- equals: equals,
- approx: approx,
- clamp: clamp,
- clamp01: clamp01,
- lerp: lerp,
- toRadian: toRadian,
- toDegree: toDegree,
- random: random,
- randomRange: randomRange,
- randomRangeInt: randomRangeInt,
- nextPow2: nextPow2
-});
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var enums = {
- // projection
- PROJ_PERSPECTIVE: 0,
- PROJ_ORTHO: 1,
-
- // lights
- LIGHT_DIRECTIONAL: 0,
- LIGHT_POINT: 1,
- LIGHT_SPOT: 2,
-
- // shadows
- SHADOW_NONE: 0,
- SHADOW_HARD: 1,
- SHADOW_SOFT: 2,
-
- // parameter type
- PARAM_INT: 0,
- PARAM_INT2: 1,
- PARAM_INT3: 2,
- PARAM_INT4: 3,
- PARAM_FLOAT: 4,
- PARAM_FLOAT2: 5,
- PARAM_FLOAT3: 6,
- PARAM_FLOAT4: 7,
- PARAM_COLOR3: 8,
- PARAM_COLOR4: 9,
- PARAM_MAT2: 10,
- PARAM_MAT3: 11,
- PARAM_MAT4: 12,
- PARAM_TEXTURE_2D: 13,
- PARAM_TEXTURE_CUBE: 14,
-
- // clear flags
- CLEAR_COLOR: 1,
- CLEAR_DEPTH: 2,
- CLEAR_STENCIL: 4,
-};
-
-var GL_NEAREST = 9728; // gl.NEAREST
-var GL_LINEAR = 9729; // gl.LINEAR
-var GL_NEAREST_MIPMAP_NEAREST = 9984; // gl.NEAREST_MIPMAP_NEAREST
-var GL_LINEAR_MIPMAP_NEAREST = 9985; // gl.LINEAR_MIPMAP_NEAREST
-var GL_NEAREST_MIPMAP_LINEAR = 9986; // gl.NEAREST_MIPMAP_LINEAR
-var GL_LINEAR_MIPMAP_LINEAR = 9987; // gl.LINEAR_MIPMAP_LINEAR
-
-// const GL_BYTE = 5120; // gl.BYTE
-var GL_UNSIGNED_BYTE = 5121; // gl.UNSIGNED_BYTE
-// const GL_SHORT = 5122; // gl.SHORT
-var GL_UNSIGNED_SHORT = 5123; // gl.UNSIGNED_SHORT
-var GL_UNSIGNED_INT = 5125; // gl.UNSIGNED_INT
-var GL_FLOAT = 5126; // gl.FLOAT
-var GL_UNSIGNED_SHORT_5_6_5 = 33635; // gl.UNSIGNED_SHORT_5_6_5
-var GL_UNSIGNED_SHORT_4_4_4_4 = 32819; // gl.UNSIGNED_SHORT_4_4_4_4
-var GL_UNSIGNED_SHORT_5_5_5_1 = 32820; // gl.UNSIGNED_SHORT_5_5_5_1
-var GL_HALF_FLOAT_OES = 36193; // gl.HALF_FLOAT_OES
-
-var GL_DEPTH_COMPONENT = 6402; // gl.DEPTH_COMPONENT
-
-var GL_ALPHA = 6406; // gl.ALPHA
-var GL_RGB = 6407; // gl.RGB
-var GL_RGBA = 6408; // gl.RGBA
-var GL_LUMINANCE = 6409; // gl.LUMINANCE
-var GL_LUMINANCE_ALPHA = 6410; // gl.LUMINANCE_ALPHA
-
-var GL_COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0; // ext.COMPRESSED_RGB_S3TC_DXT1_EXT
-var GL_COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1; // ext.COMPRESSED_RGBA_S3TC_DXT1_EXT
-var GL_COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2; // ext.COMPRESSED_RGBA_S3TC_DXT3_EXT
-var GL_COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3; // ext.COMPRESSED_RGBA_S3TC_DXT5_EXT
-
-var GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00; // ext.COMPRESSED_RGB_PVRTC_4BPPV1_IMG
-var GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG = 0x8C01; // ext.COMPRESSED_RGB_PVRTC_2BPPV1_IMG
-var GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02; // ext.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG
-var GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG = 0x8C03; // ext.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG
-
-var GL_COMPRESSED_RGB_ETC1_WEBGL = 0x8D64; // ext.COMPRESSED_RGB_ETC1_WEBGL
-
-var _filterGL = [
- [ GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR ],
- [ GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR ] ];
-
-var _textureFmtGL = [
- // TEXTURE_FMT_RGB_DXT1: 0
- { format: GL_RGB, internalFormat: GL_COMPRESSED_RGB_S3TC_DXT1_EXT, pixelType: null },
-
- // TEXTURE_FMT_RGBA_DXT1: 1
- { format: GL_RGBA, internalFormat: GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, pixelType: null },
-
- // TEXTURE_FMT_RGBA_DXT3: 2
- { format: GL_RGBA, internalFormat: GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, pixelType: null },
-
- // TEXTURE_FMT_RGBA_DXT5: 3
- { format: GL_RGBA, internalFormat: GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, pixelType: null },
-
- // TEXTURE_FMT_RGB_ETC1: 4
- { format: GL_RGB, internalFormat: GL_COMPRESSED_RGB_ETC1_WEBGL, pixelType: null },
-
- // TEXTURE_FMT_RGB_PVRTC_2BPPV1: 5
- { format: GL_RGB, internalFormat: GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG, pixelType: null },
-
- // TEXTURE_FMT_RGBA_PVRTC_2BPPV1: 6
- { format: GL_RGBA, internalFormat: GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, pixelType: null },
-
- // TEXTURE_FMT_RGB_PVRTC_4BPPV1: 7
- { format: GL_RGB, internalFormat: GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG, pixelType: null },
-
- // TEXTURE_FMT_RGBA_PVRTC_4BPPV1: 8
- { format: GL_RGBA, internalFormat: GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, pixelType: null },
-
- // TEXTURE_FMT_A8: 9
- { format: GL_ALPHA, internalFormat: GL_ALPHA, pixelType: GL_UNSIGNED_BYTE },
-
- // TEXTURE_FMT_L8: 10
- { format: GL_LUMINANCE, internalFormat: GL_LUMINANCE, pixelType: GL_UNSIGNED_BYTE },
-
- // TEXTURE_FMT_L8_A8: 11
- { format: GL_LUMINANCE_ALPHA, internalFormat: GL_LUMINANCE_ALPHA, pixelType: GL_UNSIGNED_BYTE },
-
- // TEXTURE_FMT_R5_G6_B5: 12
- { format: GL_RGB, internalFormat: GL_RGB, pixelType: GL_UNSIGNED_SHORT_5_6_5 },
-
- // TEXTURE_FMT_R5_G5_B5_A1: 13
- { format: GL_RGBA, internalFormat: GL_RGBA, pixelType: GL_UNSIGNED_SHORT_5_5_5_1 },
-
- // TEXTURE_FMT_R4_G4_B4_A4: 14
- { format: GL_RGBA, internalFormat: GL_RGBA, pixelType: GL_UNSIGNED_SHORT_4_4_4_4 },
-
- // TEXTURE_FMT_RGB8: 15
- { format: GL_RGB, internalFormat: GL_RGB, pixelType: GL_UNSIGNED_BYTE },
-
- // TEXTURE_FMT_RGBA8: 16
- { format: GL_RGBA, internalFormat: GL_RGBA, pixelType: GL_UNSIGNED_BYTE },
-
- // TEXTURE_FMT_RGB16F: 17
- { format: GL_RGB, internalFormat: GL_RGB, pixelType: GL_HALF_FLOAT_OES },
-
- // TEXTURE_FMT_RGBA16F: 18
- { format: GL_RGBA, internalFormat: GL_RGBA, pixelType: GL_HALF_FLOAT_OES },
-
- // TEXTURE_FMT_RGB32F: 19
- { format: GL_RGB, internalFormat: GL_RGB, pixelType: GL_FLOAT },
-
- // TEXTURE_FMT_RGBA32F: 20
- { format: GL_RGBA, internalFormat: GL_RGBA, pixelType: GL_FLOAT },
-
- // TEXTURE_FMT_R32F: 21
- { format: null, internalFormat: null, pixelType: null },
-
- // TEXTURE_FMT_111110F: 22
- { format: null, internalFormat: null, pixelType: null },
-
- // TEXTURE_FMT_SRGB: 23
- { format: null, internalFormat: null, pixelType: null },
-
- // TEXTURE_FMT_SRGBA: 24
- { format: null, internalFormat: null, pixelType: null },
-
- // TEXTURE_FMT_D16: 25
- { format: GL_DEPTH_COMPONENT, internalFormat: GL_DEPTH_COMPONENT, pixelType: GL_UNSIGNED_SHORT },
-
- // TEXTURE_FMT_D32: 26
- { format: GL_DEPTH_COMPONENT, internalFormat: GL_DEPTH_COMPONENT, pixelType: GL_UNSIGNED_INT },
-
- // TEXTURE_FMT_D24S8: 27
- { format: null, internalFormat: null, pixelType: null } ];
-
-/**
- * enums
- */
-var enums$1 = {
- // buffer usage
- USAGE_STATIC: 35044, // gl.STATIC_DRAW
- USAGE_DYNAMIC: 35048, // gl.DYNAMIC_DRAW
- USAGE_STREAM: 35040, // gl.STREAM_DRAW
-
- // index buffer format
- INDEX_FMT_UINT8: 5121, // gl.UNSIGNED_BYTE
- INDEX_FMT_UINT16: 5123, // gl.UNSIGNED_SHORT
- INDEX_FMT_UINT32: 5125, // gl.UNSIGNED_INT (OES_element_index_uint)
-
- // vertex attribute semantic
- ATTR_POSITION: 'a_position',
- ATTR_NORMAL: 'a_normal',
- ATTR_TANGENT: 'a_tangent',
- ATTR_BITANGENT: 'a_bitangent',
- ATTR_WEIGHTS: 'a_weights',
- ATTR_JOINTS: 'a_joints',
- ATTR_COLOR: 'a_color',
- ATTR_COLOR0: 'a_color0',
- ATTR_COLOR1: 'a_color1',
- ATTR_UV: 'a_uv',
- ATTR_UV0: 'a_uv0',
- ATTR_UV1: 'a_uv1',
- ATTR_UV2: 'a_uv2',
- ATTR_UV3: 'a_uv3',
- ATTR_UV4: 'a_uv4',
- ATTR_UV5: 'a_uv5',
- ATTR_UV6: 'a_uv6',
- ATTR_UV7: 'a_uv7',
-
- // vertex attribute type
- ATTR_TYPE_INT8: 5120, // gl.BYTE
- ATTR_TYPE_UINT8: 5121, // gl.UNSIGNED_BYTE
- ATTR_TYPE_INT16: 5122, // gl.SHORT
- ATTR_TYPE_UINT16: 5123, // gl.UNSIGNED_SHORT
- ATTR_TYPE_INT32: 5124, // gl.INT
- ATTR_TYPE_UINT32: 5125, // gl.UNSIGNED_INT
- ATTR_TYPE_FLOAT32: 5126, // gl.FLOAT
-
- // texture filter
- FILTER_NEAREST: 0,
- FILTER_LINEAR: 1,
-
- // texture wrap mode
- WRAP_REPEAT: 10497, // gl.REPEAT
- WRAP_CLAMP: 33071, // gl.CLAMP_TO_EDGE
- WRAP_MIRROR: 33648, // gl.MIRRORED_REPEAT
-
- // texture format
- // compress formats
- TEXTURE_FMT_RGB_DXT1: 0,
- TEXTURE_FMT_RGBA_DXT1: 1,
- TEXTURE_FMT_RGBA_DXT3: 2,
- TEXTURE_FMT_RGBA_DXT5: 3,
- TEXTURE_FMT_RGB_ETC1: 4,
- TEXTURE_FMT_RGB_PVRTC_2BPPV1: 5,
- TEXTURE_FMT_RGBA_PVRTC_2BPPV1: 6,
- TEXTURE_FMT_RGB_PVRTC_4BPPV1: 7,
- TEXTURE_FMT_RGBA_PVRTC_4BPPV1: 8,
-
- // normal formats
- TEXTURE_FMT_A8: 9,
- TEXTURE_FMT_L8: 10,
- TEXTURE_FMT_L8_A8: 11,
- TEXTURE_FMT_R5_G6_B5: 12,
- TEXTURE_FMT_R5_G5_B5_A1: 13,
- TEXTURE_FMT_R4_G4_B4_A4: 14,
- TEXTURE_FMT_RGB8: 15,
- TEXTURE_FMT_RGBA8: 16,
- TEXTURE_FMT_RGB16F: 17,
- TEXTURE_FMT_RGBA16F: 18,
- TEXTURE_FMT_RGB32F: 19,
- TEXTURE_FMT_RGBA32F: 20,
- TEXTURE_FMT_R32F: 21,
- TEXTURE_FMT_111110F: 22,
- TEXTURE_FMT_SRGB: 23,
- TEXTURE_FMT_SRGBA: 24,
-
- // depth formats
- TEXTURE_FMT_D16: 25,
- TEXTURE_FMT_D32: 26,
- TEXTURE_FMT_D24S8: 27,
-
- // depth and stencil function
- DS_FUNC_NEVER: 512, // gl.NEVER
- DS_FUNC_LESS: 513, // gl.LESS
- DS_FUNC_EQUAL: 514, // gl.EQUAL
- DS_FUNC_LEQUAL: 515, // gl.LEQUAL
- DS_FUNC_GREATER: 516, // gl.GREATER
- DS_FUNC_NOTEQUAL: 517, // gl.NOTEQUAL
- DS_FUNC_GEQUAL: 518, // gl.GEQUAL
- DS_FUNC_ALWAYS: 519, // gl.ALWAYS
-
- // render-buffer format
- RB_FMT_RGBA4: 32854, // gl.RGBA4
- RB_FMT_RGB5_A1: 32855, // gl.RGB5_A1
- RB_FMT_RGB565: 36194, // gl.RGB565
- RB_FMT_D16: 33189, // gl.DEPTH_COMPONENT16
- RB_FMT_S8: 36168, // gl.STENCIL_INDEX8
- RB_FMT_D24S8: 34041, // gl.DEPTH_STENCIL
-
- // blend-equation
- BLEND_FUNC_ADD: 32774, // gl.FUNC_ADD
- BLEND_FUNC_SUBTRACT: 32778, // gl.FUNC_SUBTRACT
- BLEND_FUNC_REVERSE_SUBTRACT: 32779, // gl.FUNC_REVERSE_SUBTRACT
-
- // blend
- BLEND_ZERO: 0, // gl.ZERO
- BLEND_ONE: 1, // gl.ONE
- BLEND_SRC_COLOR: 768, // gl.SRC_COLOR
- BLEND_ONE_MINUS_SRC_COLOR: 769, // gl.ONE_MINUS_SRC_COLOR
- BLEND_DST_COLOR: 774, // gl.DST_COLOR
- BLEND_ONE_MINUS_DST_COLOR: 775, // gl.ONE_MINUS_DST_COLOR
- BLEND_SRC_ALPHA: 770, // gl.SRC_ALPHA
- BLEND_ONE_MINUS_SRC_ALPHA: 771, // gl.ONE_MINUS_SRC_ALPHA
- BLEND_DST_ALPHA: 772, // gl.DST_ALPHA
- BLEND_ONE_MINUS_DST_ALPHA: 773, // gl.ONE_MINUS_DST_ALPHA
- BLEND_CONSTANT_COLOR: 32769, // gl.CONSTANT_COLOR
- BLEND_ONE_MINUS_CONSTANT_COLOR: 32770, // gl.ONE_MINUS_CONSTANT_COLOR
- BLEND_CONSTANT_ALPHA: 32771, // gl.CONSTANT_ALPHA
- BLEND_ONE_MINUS_CONSTANT_ALPHA: 32772, // gl.ONE_MINUS_CONSTANT_ALPHA
- BLEND_SRC_ALPHA_SATURATE: 776, // gl.SRC_ALPHA_SATURATE
-
- // stencil operation
- STENCIL_OP_KEEP: 7680, // gl.KEEP
- STENCIL_OP_ZERO: 0, // gl.ZERO
- STENCIL_OP_REPLACE: 7681, // gl.REPLACE
- STENCIL_OP_INCR: 7682, // gl.INCR
- STENCIL_OP_INCR_WRAP: 34055, // gl.INCR_WRAP
- STENCIL_OP_DECR: 7683, // gl.DECR
- STENCIL_OP_DECR_WRAP: 34056, // gl.DECR_WRAP
- STENCIL_OP_INVERT: 5386, // gl.INVERT
-
- // cull
- CULL_NONE: 0,
- CULL_FRONT: 1028,
- CULL_BACK: 1029,
- CULL_FRONT_AND_BACK: 1032,
-
- // primitive type
- PT_POINTS: 0, // gl.POINTS
- PT_LINES: 1, // gl.LINES
- PT_LINE_LOOP: 2, // gl.LINE_LOOP
- PT_LINE_STRIP: 3, // gl.LINE_STRIP
- PT_TRIANGLES: 4, // gl.TRIANGLES
- PT_TRIANGLE_STRIP: 5, // gl.TRIANGLE_STRIP
- PT_TRIANGLE_FAN: 6, // gl.TRIANGLE_FAN
-};
-
-/**
- * @method attrTypeBytes
- * @param {ATTR_TYPE_*} attrType
- */
-function attrTypeBytes(attrType) {
- if (attrType === enums$1.ATTR_TYPE_INT8) {
- return 1;
- } else if (attrType === enums$1.ATTR_TYPE_UINT8) {
- return 1;
- } else if (attrType === enums$1.ATTR_TYPE_INT16) {
- return 2;
- } else if (attrType === enums$1.ATTR_TYPE_UINT16) {
- return 2;
- } else if (attrType === enums$1.ATTR_TYPE_INT32) {
- return 4;
- } else if (attrType === enums$1.ATTR_TYPE_UINT32) {
- return 4;
- } else if (attrType === enums$1.ATTR_TYPE_FLOAT32) {
- return 4;
- }
-
- console.warn(("Unknown ATTR_TYPE: " + attrType));
- return 0;
-}
-
-/**
- * @method glFilter
- * @param {WebGLContext} gl
- * @param {FILTER_*} filter
- * @param {FILTER_*} mipFilter
- */
-function glFilter(gl, filter, mipFilter) {
- if ( mipFilter === void 0 ) mipFilter = -1;
-
- var result = _filterGL[filter][mipFilter+1];
- if (result === undefined) {
- console.warn(("Unknown FILTER: " + filter));
- return mipFilter === -1 ? gl.LINEAR : gl.LINEAR_MIPMAP_LINEAR;
- }
-
- return result;
-}
-
-/**
- * @method glTextureFmt
- * @param {TEXTURE_FMT_*} fmt
- */
-function glTextureFmt(fmt) {
- var result = _textureFmtGL[fmt];
- if (result === undefined) {
- console.warn(("Unknown TEXTURE_FMT: " + fmt));
- return _textureFmtGL[enums$1.TEXTURE_FMT_RGBA8];
- }
-
- return result;
-}
-
-// ====================
-// exports
-// ====================
-
-var VertexFormat = function VertexFormat(infos) {
- var this$1 = this;
-
- this._attr2el = {};
- this._elements = [];
- this._bytes = 0;
-
- var offset = 0;
- for (var i = 0, len = infos.length; i < len; ++i) {
- var info = infos[i];
- var el = {
- name: info.name,
- offset: offset,
- stride: 0,
- stream: -1,
- type: info.type,
- num: info.num,
- normalize: (info.normalize === undefined) ? false : info.normalize,
- bytes: info.num * attrTypeBytes(info.type),
- };
-
- this$1._attr2el[el.name] = el;
- this$1._elements.push(el);
-
- this$1._bytes += el.bytes;
- offset += el.bytes;
- }
-
- for (var i$1 = 0, len$1 = this._elements.length; i$1 < len$1; ++i$1) {
- var el$1 = this$1._elements[i$1];
- el$1.stride = this$1._bytes;
- }
-};
-
-/**
- * @method element
- * @param {string} attrName
- */
-VertexFormat.prototype.element = function element (attrName) {
- return this._attr2el[attrName];
-};
-
-var IndexBuffer = function IndexBuffer(device, format, usage, data, numIndices) {
- this._device = device;
- this._format = format;
- this._usage = usage;
- this._numIndices = numIndices;
- this._bytesPerIndex = 0;
-
- // calculate bytes
- if (format === enums$1.INDEX_FMT_UINT8) {
- this._bytesPerIndex = 1;
- } else if (format === enums$1.INDEX_FMT_UINT16) {
- this._bytesPerIndex = 2;
- } else if (format === enums$1.INDEX_FMT_UINT32) {
- this._bytesPerIndex = 4;
- }
- this._bytes = this._bytesPerIndex * numIndices;
-
- // update
- this._glID = device._gl.createBuffer();
- this.update(0, data);
-
- // stats
- device._stats.ib += this._bytes;
-};
-
-var prototypeAccessors = { count: { configurable: true } };
-
-/**
- * @method destroy
- */
-IndexBuffer.prototype.destroy = function destroy () {
- if (this._glID === -1) {
- console.error('The buffer already destroyed');
- return;
- }
-
- var gl = this._device._gl;
- gl.deleteBuffer(this._glID);
- this._device._stats.ib -= this.bytes;
-
- this._glID = -1;
-};
-
-/**
- * @method update
- * @param {Number} offset
- * @param {ArrayBuffer} data
- */
-IndexBuffer.prototype.update = function update (offset, data) {
- if (this._glID === -1) {
- console.error('The buffer is destroyed');
- return;
- }
-
- if (data && data.byteLength + offset > this._bytes) {
- console.error('Failed to update data, bytes exceed.');
- return;
- }
-
- var gl = this._device._gl;
- var glUsage = this._usage;
-
- gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._glID);
- if (!data) {
- if (this._bytes) {
- gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._bytes, glUsage);
- } else {
- console.warn('bufferData should not submit 0 bytes data');
- }
- } else {
- if (offset) {
- gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, offset, data);
- } else {
- gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, data, glUsage);
- }
- }
- this._device._restoreIndexBuffer();
-};
-
-prototypeAccessors.count.get = function () {
- return this._numIndices;
-};
-
-Object.defineProperties( IndexBuffer.prototype, prototypeAccessors );
-
-var VertexBuffer = function VertexBuffer(device, format, usage, data, numVertices) {
- this._device = device;
- this._format = format;
- this._usage = usage;
- this._numVertices = numVertices;
-
- // calculate bytes
- this._bytes = this._format._bytes * numVertices;
-
- // update
- this._glID = device._gl.createBuffer();
- this.update(0, data);
-
- // stats
- device._stats.vb += this._bytes;
-};
-
-var prototypeAccessors$1 = { count: { configurable: true } };
-
-/**
- * @method destroy
- */
-VertexBuffer.prototype.destroy = function destroy () {
- if (this._glID === -1) {
- console.error('The buffer already destroyed');
- return;
- }
-
- var gl = this._device._gl;
- gl.deleteBuffer(this._glID);
- this._device._stats.vb -= this.bytes;
-
- this._glID = -1;
-};
-
-/**
- * @method update
- * @param {Number} offset
- * @param {ArrayBuffer} data
- */
-VertexBuffer.prototype.update = function update (offset, data) {
- if (this._glID === -1) {
- console.error('The buffer is destroyed');
- return;
- }
-
- if (data && data.byteLength + offset > this._bytes) {
- console.error('Failed to update data, bytes exceed.');
- return;
- }
-
- var gl = this._device._gl;
- var glUsage = this._usage;
-
- gl.bindBuffer(gl.ARRAY_BUFFER, this._glID);
- if (!data) {
- if (this._bytes) {
- gl.bufferData(gl.ARRAY_BUFFER, this._bytes, glUsage);
- } else {
- console.warn('bufferData should not submit 0 bytes data');
- }
- } else {
- if (offset) {
- gl.bufferSubData(gl.ARRAY_BUFFER, offset, data);
- } else {
- gl.bufferData(gl.ARRAY_BUFFER, data, glUsage);
- }
- }
- gl.bindBuffer(gl.ARRAY_BUFFER, null);
-};
-
-prototypeAccessors$1.count.get = function () {
- return this._numVertices;
-};
-
-Object.defineProperties( VertexBuffer.prototype, prototypeAccessors$1 );
-
-var _genID = 0;
-
-function _parseError(out, type, errorLog) {
- errorLog.split('\n').forEach(function (msg) {
- if (msg.length < 5) {
- return;
- }
-
- var parts = /^ERROR\:\s+(\d+)\:(\d+)\:\s*(.*)$/.exec(msg);
- if (parts) {
- out.push({
- type: type,
- fileID: parts[1] | 0,
- line: parts[2] | 0,
- message: parts[3].trim()
- });
- } else if (msg.length > 0) {
- out.push({
- type: type,
- fileID: -1,
- line: 0,
- message: msg
- });
- }
- });
-}
-
-var Program = function Program(device, options) {
- this._device = device;
-
- // stores gl information: { location, type }
- this._attributes = [];
- this._uniforms = [];
- this._samplers = [];
- this._errors = [];
- this._linked = false;
- this._vertSource = options.vert;
- this._fragSource = options.frag;
- this._glID = null;
- this._id = _genID++;
-};
-
-var prototypeAccessors$2 = { id: { configurable: true } };
-
-prototypeAccessors$2.id.get = function () {
- return this._id;
-};
-
-Program.prototype.link = function link () {
- var this$1 = this;
-
- if (this._linked) {
- return;
- }
-
- var gl = this._device._gl;
-
- var vertShader = _createShader(gl, gl.VERTEX_SHADER, this._vertSource);
- var fragShader = _createShader(gl, gl.FRAGMENT_SHADER, this._fragSource);
-
- var program = gl.createProgram();
- gl.attachShader(program, vertShader);
- gl.attachShader(program, fragShader);
- gl.linkProgram(program);
-
- var failed = false;
- var errors = this._errors;
-
- if (!gl.getShaderParameter(vertShader, gl.COMPILE_STATUS)) {
- _parseError(errors, 'vs', gl.getShaderInfoLog(vertShader));
- failed = true;
- }
-
- if (!gl.getShaderParameter(fragShader, gl.COMPILE_STATUS)) {
- _parseError(errors, 'fs', gl.getShaderInfoLog(fragShader));
- failed = true;
- }
-
- gl.deleteShader(vertShader);
- gl.deleteShader(fragShader);
-
- if (failed) {
- errors.forEach(function (err) {
- console.error(("Failed to compile " + (err.type) + " " + (err.fileID) + " (ln " + (err.line) + "): " + (err.message)));
- });
- return;
- }
-
- if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
- console.error(("Failed to link shader program: " + (gl.getProgramInfoLog(program))));
- failed = true;
- }
-
- if (failed) {
- return;
- }
-
- this._glID = program;
-
- // parse attribute
- var numAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
- for (var i = 0; i < numAttributes; ++i) {
- var info = gl.getActiveAttrib(program, i);
- var location = gl.getAttribLocation(program, info.name);
-
- this$1._attributes.push({
- name: info.name,
- location: location,
- type: info.type,
- });
- }
-
- // parse uniform
- var numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
- for (var i$1 = 0; i$1 < numUniforms; ++i$1) {
- var info$1 = gl.getActiveUniform(program, i$1);
- var name = info$1.name;
- var location$1 = gl.getUniformLocation(program, name);
- var isArray = name.substr(name.length - 3) === '[0]';
- if (isArray) {
- name = name.substr(0, name.length - 3);
- }
-
- this$1._uniforms.push({
- name: name,
- location: location$1,
- type: info$1.type,
- size: isArray ? info$1.size : undefined, // used when uniform is an array
- });
- }
-
- this._linked = true;
-};
-
-Program.prototype.destroy = function destroy () {
- var gl = this._device._gl;
- gl.deleteProgram(this._glID);
-
- this._linked = false;
- this._glID = null;
- this._attributes = [];
- this._uniforms = [];
- this._samplers = [];
-};
-
-Object.defineProperties( Program.prototype, prototypeAccessors$2 );
-
-// ====================
-// internal
-// ====================
-
-function _createShader(gl, type, src) {
- var shader = gl.createShader(type);
- gl.shaderSource(shader, src);
- gl.compileShader(shader);
-
- return shader;
-}
-
-var Texture = function Texture(device) {
- this._device = device;
-
- this._width = 4;
- this._height = 4;
- this._hasMipmap = false;
- this._compressed = false;
-
- this._anisotropy = 1;
- this._minFilter = enums$1.FILTER_LINEAR;
- this._magFilter = enums$1.FILTER_LINEAR;
- this._mipFilter = enums$1.FILTER_LINEAR;
- this._wrapS = enums$1.WRAP_REPEAT;
- this._wrapT = enums$1.WRAP_REPEAT;
- // wrapR available in webgl2
- // this._wrapR = enums.WRAP_REPEAT;
- this._format = enums$1.TEXTURE_FMT_RGBA8;
-
- this._target = -1;
-};
-
-/**
- * @method destroy
- */
-Texture.prototype.destroy = function destroy () {
- if (this._glID === -1) {
- console.error('The texture already destroyed');
- return;
- }
-
- var gl = this._device._gl;
- gl.deleteTexture(this._glID);
-
- this._device._stats.tex -= this.bytes;
- this._glID = -1;
-};
-
-function isPow2$1(v) {
- return !(v & (v - 1)) && (!!v);
-}
-
-var Texture2D = (function (Texture$$1) {
- function Texture2D(device, options) {
- Texture$$1.call(this, device);
-
- var gl = this._device._gl;
- this._target = gl.TEXTURE_2D;
- this._glID = gl.createTexture();
-
- // always alloc texture in GPU when we create it.
- options.images = options.images || [null];
- this.update(options);
- }
-
- if ( Texture$$1 ) Texture2D.__proto__ = Texture$$1;
- Texture2D.prototype = Object.create( Texture$$1 && Texture$$1.prototype );
- Texture2D.prototype.constructor = Texture2D;
-
- /**
- * @method update
- * @param {Object} options
- * @param {Array} options.images
- * @param {Boolean} options.mipmap
- * @param {Number} options.width
- * @param {Number} options.height
- * @param {TEXTURE_FMT_*} options.format
- * @param {Number} options.anisotropy
- * @param {FILTER_*} options.minFilter
- * @param {FILTER_*} options.magFilter
- * @param {FILTER_*} options.mipFilter
- * @param {WRAP_*} options.wrapS
- * @param {WRAP_*} options.wrapT
- * @param {Boolean} options.flipY
- * @param {Boolean} options.premultiplyAlpha
- */
- Texture2D.prototype.update = function update (options) {
- var gl = this._device._gl;
- var genMipmap = this._hasMipmap;
-
- if (options) {
- if (options.width !== undefined) {
- this._width = options.width;
- }
- if (options.height !== undefined) {
- this._height = options.height;
- }
- if (options.anisotropy !== undefined) {
- this._anisotropy = options.anisotropy;
- }
- if (options.minFilter !== undefined) {
- this._minFilter = options.minFilter;
- }
- if (options.magFilter !== undefined) {
- this._magFilter = options.magFilter;
- }
- if (options.mipFilter !== undefined) {
- this._mipFilter = options.mipFilter;
- }
- if (options.wrapS !== undefined) {
- this._wrapS = options.wrapS;
- }
- if (options.wrapT !== undefined) {
- this._wrapT = options.wrapT;
- }
- if (options.format !== undefined) {
- this._format = options.format;
- this._compressed = (
- this._format >= enums$1.TEXTURE_FMT_RGB_DXT1 &&
- this._format <= enums$1.TEXTURE_FMT_RGBA_PVRTC_4BPPV1
- );
- }
-
- // check if generate mipmap
- if (options.mipmap !== undefined) {
- this._hasMipmap = options.mipmap;
- genMipmap = options.mipmap;
- }
-
- if (options.images !== undefined) {
- if (options.images.length > 1) {
- genMipmap = false;
- var maxLength = options.width > options.height ? options.width : options.height;
- if (maxLength >> (options.images.length - 1) !== 1) {
- console.error('texture-2d mipmap is invalid, should have a 1x1 mipmap.');
- }
- }
- }
- }
-
- // NOTE: get pot after this._width, this._height has been assigned.
- var pot = isPow2$1(this._width) && isPow2$1(this._height);
- if (!pot) {
- genMipmap = false;
- }
-
- gl.activeTexture(gl.TEXTURE0);
- gl.bindTexture(gl.TEXTURE_2D, this._glID);
- if (options.images !== undefined && options.images.length > 0) {
- this._setMipmap(options.images, options.flipY, options.premultiplyAlpha);
- }
-
- this._setTexInfo();
-
- if (genMipmap) {
- gl.hint(gl.GENERATE_MIPMAP_HINT, gl.NICEST);
- gl.generateMipmap(gl.TEXTURE_2D);
- }
- this._device._restoreTexture(0);
- };
-
- /**
- * @method updateSubImage
- * @param {Object} options
- * @param {Number} options.x
- * @param {Number} options.y
- * @param {Number} options.width
- * @param {Number} options.height
- * @param {Number} options.level
- * @param {HTMLCanvasElement | HTMLImageElement | HTMLVideoElement | ArrayBufferView} options.image
- * @param {Boolean} options.flipY
- * @param {Boolean} options.premultiplyAlpha
- */
- Texture2D.prototype.updateSubImage = function updateSubImage (options) {
- var gl = this._device._gl;
- var glFmt = glTextureFmt(this._format);
-
- gl.activeTexture(gl.TEXTURE0);
- gl.bindTexture(gl.TEXTURE_2D, this._glID);
- this._setSubImage(glFmt, options);
- this._device._restoreTexture(0);
- };
-
- /**
- * @method updateImage
- * @param {Object} options
- * @param {Number} options.width
- * @param {Number} options.height
- * @param {Number} options.level
- * @param {HTMLCanvasElement | HTMLImageElement | HTMLVideoElement | ArrayBufferView} options.image
- * @param {Boolean} options.flipY
- * @param {Boolean} options.premultiplyAlpha
- */
- Texture2D.prototype.updateImage = function updateImage (options) {
- var gl = this._device._gl;
- var glFmt = glTextureFmt(this._format);
-
- gl.activeTexture(gl.TEXTURE0);
- gl.bindTexture(gl.TEXTURE_2D, this._glID);
- this._setImage(glFmt, options);
- this._device._restoreTexture(0);
- };
-
- Texture2D.prototype._setSubImage = function _setSubImage (glFmt, options) {
- var gl = this._device._gl;
- var flipY = options.flipY;
- var premultiplyAlpha = options.premultiplyAlpha;
- var img = options.image;
-
- if (
- img instanceof HTMLCanvasElement ||
- img instanceof HTMLImageElement ||
- img instanceof HTMLVideoElement
- ) {
- if (flipY === undefined) {
- gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
- } else {
- gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
- }
-
- if (premultiplyAlpha === undefined) {
- gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
- } else {
- gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, premultiplyAlpha);
- }
-
- gl.texSubImage2D(gl.TEXTURE_2D, options.level, options.x, options.y, glFmt.format, glFmt.pixelType, img);
- } else {
- if (flipY === undefined) {
- gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
- } else {
- gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
- }
-
- if (premultiplyAlpha === undefined) {
- gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
- } else {
- gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, premultiplyAlpha);
- }
-
- if (this._compressed) {
- gl.compressedTexSubImage2D(gl.TEXTURE_2D,
- options.level,
- options.x,
- options.y,
- options.width,
- options.height,
- glFmt.format,
- img
- );
- } else {
- gl.texSubImage2D(
- gl.TEXTURE_2D,
- options.level,
- options.x,
- options.y,
- options.width,
- options.height,
- glFmt.format,
- glFmt.pixelType,
- img
- );
- }
- }
- };
-
- Texture2D.prototype._setImage = function _setImage (glFmt, options) {
- var gl = this._device._gl;
- var flipY = options.flipY;
- var premultiplyAlpha = options.premultiplyAlpha;
- var img = options.image;
-
- if (
- img instanceof HTMLCanvasElement ||
- img instanceof HTMLImageElement ||
- img instanceof HTMLVideoElement
- ) {
- if (flipY === undefined) {
- gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
- } else {
- gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
- }
-
- if (premultiplyAlpha === undefined) {
- gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
- } else {
- gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, premultiplyAlpha);
- }
-
- gl.texImage2D(
- gl.TEXTURE_2D,
- options.level,
- glFmt.internalFormat,
- glFmt.format,
- glFmt.pixelType,
- img
- );
- } else {
- if (flipY === undefined) {
- gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
- } else {
- gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
- }
-
- if (premultiplyAlpha === undefined) {
- gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
- } else {
- gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, premultiplyAlpha);
- }
-
- if (this._compressed) {
- gl.compressedTexImage2D(
- gl.TEXTURE_2D,
- options.level,
- glFmt.internalFormat,
- options.width,
- options.height,
- 0,
- img
- );
- } else {
- gl.texImage2D(
- gl.TEXTURE_2D,
- options.level,
- glFmt.internalFormat,
- options.width,
- options.height,
- 0,
- glFmt.format,
- glFmt.pixelType,
- img
- );
- }
- }
- };
-
- Texture2D.prototype._setMipmap = function _setMipmap (images, flipY, premultiplyAlpha) {
- var this$1 = this;
-
- var glFmt = glTextureFmt(this._format);
- var options = {
- width: this._width,
- height: this._height,
- flipY: flipY,
- premultiplyAlpha: premultiplyAlpha,
- level: 0,
- image: null
- };
-
- for (var i = 0; i < images.length; ++i) {
- options.level = i;
- options.width = this$1._width >> i;
- options.height = this$1._height >> i;
- options.image = images[i];
- this$1._setImage(glFmt, options);
- }
- };
-
- Texture2D.prototype._setTexInfo = function _setTexInfo () {
- var gl = this._device._gl;
- var pot = isPow2$1(this._width) && isPow2$1(this._height);
-
- // WebGL1 doesn't support all wrap modes with NPOT textures
- if (!pot && (this._wrapS !== enums$1.WRAP_CLAMP || this._wrapT !== enums$1.WRAP_CLAMP)) {
- console.warn('WebGL1 doesn\'t support all wrap modes with NPOT textures');
- this._wrapS = enums$1.WRAP_CLAMP;
- this._wrapT = enums$1.WRAP_CLAMP;
- }
-
- var mipFilter = this._hasMipmap ? this._mipFilter : -1;
- if (!pot && mipFilter !== -1) {
- console.warn('NPOT textures do not support mipmap filter');
- mipFilter = -1;
- }
-
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, glFilter(gl, this._minFilter, mipFilter));
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, glFilter(gl, this._magFilter, -1));
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, this._wrapS);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, this._wrapT);
-
- var ext = this._device.ext('EXT_texture_filter_anisotropic');
- if (ext) {
- gl.texParameteri(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT, this._anisotropy);
- }
- };
-
- return Texture2D;
-}(Texture));
-
-var TextureCube = (function (Texture$$1) {
- function TextureCube(device, options) {
- Texture$$1.call(this, device);
- var gl = this._device._gl;
- this._target = gl.TEXTURE_CUBE_MAP;
- this._glID = gl.createTexture();
- this.update(options);
- }
-
- if ( Texture$$1 ) TextureCube.__proto__ = Texture$$1;
- TextureCube.prototype = Object.create( Texture$$1 && Texture$$1.prototype );
- TextureCube.prototype.constructor = TextureCube;
-
- /**
- * @method update
- * @param {Object} options
- * @param {Array} options.images
- * @param {Boolean} options.mipmap
- * @param {Number} options.width
- * @param {Number} options.height
- * @param {TEXTURE_FMT_*} options.format
- * @param {Number} options.anisotropy
- * @param {FILTER_*} options.minFilter
- * @param {FILTER_*} options.magFilter
- * @param {FILTER_*} options.mipFilter
- * @param {WRAP_*} options.wrapS
- * @param {WRAP_*} options.wrapT
- * @param {WRAP_*} options.wrapR
- * @param {Boolean} options.flipY
- * @param {Boolean} options.premultiplyAlpha
- */
- TextureCube.prototype.update = function update (options) {
- var gl = this._device._gl;
- var genMipmap = this._hasMipmap;
-
- if (options) {
- if (options.width !== undefined) {
- this._width = options.width;
- }
- if (options.height !== undefined) {
- this._height = options.height;
- }
- if (options.anisotropy !== undefined) {
- this._anisotropy = options.anisotropy;
- }
- if (options.minFilter !== undefined) {
- this._minFilter = options.minFilter;
- }
- if (options.magFilter !== undefined) {
- this._magFilter = options.magFilter;
- }
- if (options.mipFilter !== undefined) {
- this._mipFilter = options.mipFilter;
- }
- if (options.wrapS !== undefined) {
- this._wrapS = options.wrapS;
- }
- if (options.wrapT !== undefined) {
- this._wrapT = options.wrapT;
- }
- // wrapR available in webgl2
- // if (options.wrapR !== undefined) {
- // this._wrapR = options.wrapR;
- // }
- if (options.format !== undefined) {
- this._format = options.format;
- this._compressed = (
- this._format >= enums$1.TEXTURE_FMT_RGB_DXT1 &&
- this._format <= enums$1.TEXTURE_FMT_RGBA_PVRTC_4BPPV1
- );
- }
-
- // check if generate mipmap
- if (options.mipmap !== undefined) {
- this._hasMipmap = options.mipmap;
- genMipmap = options.mipmap;
- }
-
- if (options.images !== undefined) {
- if (options.images.length > 1) {
- genMipmap = false;
- if (options.width !== options.height) {
- console.warn('texture-cube width and height should be identical.');
- }
- if (options.width >> (options.images.length - 1) !== 1) {
- console.error('texture-cube mipmap is invalid. please set mipmap as 1x1, 2x2, 4x4 ... nxn');
- }
- }
- }
- }
-
- // NOTE: get pot after this._width, this._height has been assigned.
- var pot = isPow2$1(this._width) && isPow2$1(this._height);
- if (!pot) {
- genMipmap = false;
- }
-
- gl.activeTexture(gl.TEXTURE0);
- gl.bindTexture(gl.TEXTURE_CUBE_MAP, this._glID);
- if (options.images !== undefined && options.images.length > 0) {
- this._setMipmap(options.images, options.flipY, options.premultiplyAlpha);
- }
-
- this._setTexInfo();
-
- if (genMipmap) {
- gl.hint(gl.GENERATE_MIPMAP_HINT, gl.NICEST);
- gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
- }
- this._device._restoreTexture(0);
- };
-
- /**
- * @method updateSubImage
- * @param {Object} options
- * @param {Number} options.x
- * @param {Number} options.y
- * @param {Number} options.width
- * @param {Number} options.height
- * @param {Number} options.level
- * @param {Number} options.faceIndex
- * @param {HTMLCanvasElement | HTMLImageElement | HTMLVideoElement | ArrayBufferView} options.image
- * @param {Boolean} options.flipY
- * @param {Boolean} options.premultiplyAlpha
- */
- TextureCube.prototype.updateSubImage = function updateSubImage (options) {
- var gl = this._device._gl;
- var glFmt = glTextureFmt(this._format);
-
- gl.activeTexture(gl.TEXTURE0);
- gl.bindTexture(gl.TEXTURE_CUBE_MAP, this._glID);
- this._setSubImage(glFmt, options);
-
- this._device._restoreTexture(0);
- };
-
- /**
- * @method updateImage
- * @param {Object} options
- * @param {Number} options.width
- * @param {Number} options.height
- * @param {Number} options.level
- * @param {Number} options.faceIndex
- * @param {HTMLCanvasElement | HTMLImageElement | HTMLVideoElement | ArrayBufferView} options.image
- * @param {Boolean} options.flipY
- * @param {Boolean} options.premultiplyAlpha
- */
- TextureCube.prototype.updateImage = function updateImage (options) {
- var gl = this._device._gl;
- var glFmt = glTextureFmt(this._format);
-
- gl.activeTexture(gl.TEXTURE0);
- gl.bindTexture(gl.TEXTURE_CUBE_MAP, this._glID);
- this._setImage(glFmt, options);
- this._device._restoreTexture(0);
- };
-
- TextureCube.prototype._setSubImage = function _setSubImage (glFmt, options) {
- var gl = this._device._gl;
- var flipY = options.flipY;
- var premultiplyAlpha = options.premultiplyAlpha;
- var faceIndex = options.faceIndex;
- var img = options.image;
-
- if (flipY === undefined) {
- gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
- } else {
- gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
- }
-
- if (premultiplyAlpha === undefined) {
- gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
- } else {
- gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, premultiplyAlpha);
- }
-
- if (
- img instanceof HTMLCanvasElement ||
- img instanceof HTMLImageElement ||
- img instanceof HTMLVideoElement
- ) {
- gl.texSubImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, options.level, options.x, options.y, glFmt.format, glFmt.pixelType, img);
- } else {
- if (this._compressed) {
- gl.compressedTexSubImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex,
- options.level,
- options.x,
- options.y,
- options.width,
- options.height,
- glFmt.format,
- img
- );
- } else {
- gl.texSubImage2D(
- gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex,
- options.level,
- options.x,
- options.y,
- options.width,
- options.height,
- glFmt.format,
- glFmt.pixelType,
- img
- );
- }
- }
- };
-
- TextureCube.prototype._setImage = function _setImage (glFmt, options) {
- var gl = this._device._gl;
- var flipY = options.flipY;
- var premultiplyAlpha = options.premultiplyAlpha;
- var faceIndex = options.faceIndex;
- var img = options.image;
-
- if (flipY === undefined) {
- gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
- } else {
- gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
- }
-
- if (premultiplyAlpha === undefined) {
- gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
- } else {
- gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, premultiplyAlpha);
- }
- if (
- img instanceof HTMLCanvasElement ||
- img instanceof HTMLImageElement ||
- img instanceof HTMLVideoElement
- ) {
- gl.texImage2D(
- gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex,
- options.level,
- glFmt.internalFormat,
- glFmt.format,
- glFmt.pixelType,
- img
- );
- } else {
- if (this._compressed) {
- gl.compressedTexImage2D(
- gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex,
- options.level,
- glFmt.internalFormat,
- options.width,
- options.height,
- 0,
- img
- );
- } else {
- gl.texImage2D(
- gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex,
- options.level,
- glFmt.internalFormat,
- options.width,
- options.height,
- 0,
- glFmt.format,
- glFmt.pixelType,
- img
- );
- }
- }
- };
-
- // levelImages = [imagePosX, imageNegX, imagePosY, imageNegY, imagePosZ, imageNegz]
- // images = [levelImages0, levelImages1, ...]
- TextureCube.prototype._setMipmap = function _setMipmap (images, flipY, premultiplyAlpha) {
- var this$1 = this;
-
- var glFmt = glTextureFmt(this._format);
- var options = {
- width: this._width,
- height: this._height,
- faceIndex: 0,
- flipY: flipY,
- premultiplyAlpha: premultiplyAlpha,
- level: 0,
- image: null
- };
-
- for (var i = 0; i < images.length; ++i) {
- var levelImages = images[i];
- options.level = i;
- options.width = this$1._width >> i;
- options.height = this$1._height >> i;
-
- for (var face = 0; face < 6; ++face) {
- options.faceIndex = face;
- options.image = levelImages[face];
- this$1._setImage(glFmt, options);
- }
- }
- };
-
- TextureCube.prototype._setTexInfo = function _setTexInfo () {
- var gl = this._device._gl;
- var pot = isPow2$1(this._width) && isPow2$1(this._height);
-
- // WebGL1 doesn't support all wrap modes with NPOT textures
- if (!pot && (this._wrapS !== enums$1.WRAP_CLAMP || this._wrapT !== enums$1.WRAP_CLAMP)) {
- console.warn('WebGL1 doesn\'t support all wrap modes with NPOT textures');
- this._wrapS = enums$1.WRAP_CLAMP;
- this._wrapT = enums$1.WRAP_CLAMP;
- }
-
- var mipFilter = this._hasMipmap ? this._mipFilter : -1;
- if (!pot && mipFilter !== -1) {
- console.warn('NPOT textures do not support mipmap filter');
- mipFilter = -1;
- }
-
- gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, glFilter(gl, this._minFilter, mipFilter));
- gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, glFilter(gl, this._magFilter, -1));
- gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, this._wrapS);
- gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, this._wrapT);
- // wrapR available in webgl2
- // gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_R, this._wrapR);
-
- var ext = this._device.ext('EXT_texture_filter_anisotropic');
- if (ext) {
- gl.texParameteri(gl.TEXTURE_CUBE_MAP, ext.TEXTURE_MAX_ANISOTROPY_EXT, this._anisotropy);
- }
- };
-
- return TextureCube;
-}(Texture));
-
-var RenderBuffer = function RenderBuffer(device, format, width, height) {
- this._device = device;
- this._format = format;
- this._width = width;
- this._height = height;
-
- var gl = device._gl;
- this._glID = gl.createRenderbuffer();
-
- gl.bindRenderbuffer(gl.RENDERBUFFER, this._glID);
- gl.renderbufferStorage(gl.RENDERBUFFER, format, width, height);
- gl.bindRenderbuffer(gl.RENDERBUFFER, null);
-};
-
-/**
- * @method destroy
- */
-RenderBuffer.prototype.destroy = function destroy () {
- if (this._glID === null) {
- console.error('The render-buffer already destroyed');
- return;
- }
-
- var gl = this._device._gl;
-
- gl.bindRenderbuffer(gl.RENDERBUFFER, null);
- gl.deleteRenderbuffer(this._glID);
-
- this._glID = null;
-};
-
-var FrameBuffer = function FrameBuffer(device, width, height, options) {
- this._device = device;
- this._width = width;
- this._height = height;
-
- this._colors = options.colors || [];
- this._depth = options.depth || null;
- this._stencil = options.stencil || null;
- this._depthStencil = options.depthStencil || null;
-
- this._glID = device._gl.createFramebuffer();
-};
-
-/**
- * @method destroy
- */
-FrameBuffer.prototype.destroy = function destroy () {
- if (this._glID === null) {
- console.error('The frame-buffer already destroyed');
- return;
- }
-
- var gl = this._device._gl;
-
- gl.deleteFramebuffer(this._glID);
-
- this._glID = null;
-};
-
-var _default = {
- // blend
- blend: false,
- blendSep: false,
- blendColor: 0xffffffff,
- blendEq: enums$1.BLEND_FUNC_ADD,
- blendAlphaEq: enums$1.BLEND_FUNC_ADD,
- blendSrc: enums$1.BLEND_ONE,
- blendDst: enums$1.BLEND_ZERO,
- blendSrcAlpha: enums$1.BLEND_ONE,
- blendDstAlpha: enums$1.BLEND_ZERO,
-
- // depth
- depthTest: false,
- depthWrite: false,
- depthFunc: enums$1.DS_FUNC_LESS,
-
- // stencil
- stencilTest: false,
- stencilSep: false,
- stencilFuncFront: enums$1.DS_FUNC_ALWAYS,
- stencilRefFront: 0,
- stencilMaskFront: 0xff,
- stencilFailOpFront: enums$1.STENCIL_OP_KEEP,
- stencilZFailOpFront: enums$1.STENCIL_OP_KEEP,
- stencilZPassOpFront: enums$1.STENCIL_OP_KEEP,
- stencilWriteMaskFront: 0xff,
- stencilFuncBack: enums$1.DS_FUNC_ALWAYS,
- stencilRefBack: 0,
- stencilMaskBack: 0xff,
- stencilFailOpBack: enums$1.STENCIL_OP_KEEP,
- stencilZFailOpBack: enums$1.STENCIL_OP_KEEP,
- stencilZPassOpBack: enums$1.STENCIL_OP_KEEP,
- stencilWriteMaskBack: 0xff,
-
- // cull-mode
- cullMode: enums$1.CULL_BACK,
-
- // primitive-type
- primitiveType: enums$1.PT_TRIANGLES,
-
- // bindings
- maxStream: -1,
- vertexBuffers: [],
- vertexBufferOffsets: [],
- indexBuffer: null,
- maxTextureSlot: -1,
- textureUnits: [],
- program: null,
-};
-
-var State = function State(device) {
- // bindings
- this.vertexBuffers = new Array(device._caps.maxVertexStreams);
- this.vertexBufferOffsets = new Array(device._caps.maxVertexStreams);
- this.textureUnits = new Array(device._caps.maxTextureUnits);
-
- this.set(_default);
-};
-
-State.initDefault = function initDefault (device) {
- _default.vertexBuffers = new Array(device._caps.maxVertexStreams);
- _default.vertexBufferOffsets = new Array(device._caps.maxVertexStreams);
- _default.textureUnits = new Array(device._caps.maxTextureUnits);
-};
-
-State.prototype.reset = function reset () {
- this.set(_default);
-};
-
-State.prototype.set = function set (cpy) {
- var this$1 = this;
-
- // blending
- this.blend = cpy.blend;
- this.blendSep = cpy.blendSep;
- this.blendColor = cpy.blendColor;
- this.blendEq = cpy.blendEq;
- this.blendAlphaEq = cpy.blendAlphaEq;
- this.blendSrc = cpy.blendSrc;
- this.blendDst = cpy.blendDst;
- this.blendSrcAlpha = cpy.blendSrcAlpha;
- this.blendDstAlpha = cpy.blendDstAlpha;
-
- // depth
- this.depthTest = cpy.depthTest;
- this.depthWrite = cpy.depthWrite;
- this.depthFunc = cpy.depthFunc;
-
- // stencil
- this.stencilTest = cpy.stencilTest;
- this.stencilSep = cpy.stencilSep;
- this.stencilFuncFront = cpy.stencilFuncFront;
- this.stencilRefFront = cpy.stencilRefFront;
- this.stencilMaskFront = cpy.stencilMaskFront;
- this.stencilFailOpFront = cpy.stencilFailOpFront;
- this.stencilZFailOpFront = cpy.stencilZFailOpFront;
- this.stencilZPassOpFront = cpy.stencilZPassOpFront;
- this.stencilWriteMaskFront = cpy.stencilWriteMaskFront;
- this.stencilFuncBack = cpy.stencilFuncBack;
- this.stencilRefBack = cpy.stencilRefBack;
- this.stencilMaskBack = cpy.stencilMaskBack;
- this.stencilFailOpBack = cpy.stencilFailOpBack;
- this.stencilZFailOpBack = cpy.stencilZFailOpBack;
- this.stencilZPassOpBack = cpy.stencilZPassOpBack;
- this.stencilWriteMaskBack = cpy.stencilWriteMaskBack;
-
- // cull-mode
- this.cullMode = cpy.cullMode;
-
- // primitive-type
- this.primitiveType = cpy.primitiveType;
-
- // buffer bindings
- this.maxStream = cpy.maxStream;
- for (var i = 0; i < cpy.vertexBuffers.length; ++i) {
- this$1.vertexBuffers[i] = cpy.vertexBuffers[i];
- }
- for (var i$1 = 0; i$1 < cpy.vertexBufferOffsets.length; ++i$1) {
- this$1.vertexBufferOffsets[i$1] = cpy.vertexBufferOffsets[i$1];
- }
- this.indexBuffer = cpy.indexBuffer;
-
- // texture bindings
- this.maxTextureSlot = cpy.maxTextureSlot;
- for (var i$2 = 0; i$2 < cpy.textureUnits.length; ++i$2) {
- this$1.textureUnits[i$2] = cpy.textureUnits[i$2];
- }
-
- this.program = cpy.program;
-};
-
-var GL_INT = 5124;
-var GL_FLOAT$1 = 5126;
-var GL_FLOAT_VEC2 = 35664;
-var GL_FLOAT_VEC3 = 35665;
-var GL_FLOAT_VEC4 = 35666;
-var GL_INT_VEC2 = 35667;
-var GL_INT_VEC3 = 35668;
-var GL_INT_VEC4 = 35669;
-var GL_BOOL = 35670;
-var GL_BOOL_VEC2 = 35671;
-var GL_BOOL_VEC3 = 35672;
-var GL_BOOL_VEC4 = 35673;
-var GL_FLOAT_MAT2 = 35674;
-var GL_FLOAT_MAT3 = 35675;
-var GL_FLOAT_MAT4 = 35676;
-var GL_SAMPLER_2D = 35678;
-var GL_SAMPLER_CUBE = 35680;
-
-/**
- * _type2uniformCommit
- */
-var _type2uniformCommit = {};
-_type2uniformCommit[GL_INT] = function (gl, id, value) {
- gl.uniform1i(id, value);
- };
-_type2uniformCommit[GL_FLOAT$1] = function (gl, id, value) {
- gl.uniform1f(id, value);
- };
-_type2uniformCommit[GL_FLOAT_VEC2] = function (gl, id, value) {
- gl.uniform2fv(id, value);
- };
-_type2uniformCommit[GL_FLOAT_VEC3] = function (gl, id, value) {
- gl.uniform3fv(id, value);
- };
-_type2uniformCommit[GL_FLOAT_VEC4] = function (gl, id, value) {
- gl.uniform4fv(id, value);
- };
-_type2uniformCommit[GL_INT_VEC2] = function (gl, id, value) {
- gl.uniform2iv(id, value);
- };
-_type2uniformCommit[GL_INT_VEC3] = function (gl, id, value) {
- gl.uniform3iv(id, value);
- };
-_type2uniformCommit[GL_INT_VEC4] = function (gl, id, value) {
- gl.uniform4iv(id, value);
- };
-_type2uniformCommit[GL_BOOL] = function (gl, id, value) {
- gl.uniform1i(id, value);
- };
-_type2uniformCommit[GL_BOOL_VEC2] = function (gl, id, value) {
- gl.uniform2iv(id, value);
- };
-_type2uniformCommit[GL_BOOL_VEC3] = function (gl, id, value) {
- gl.uniform3iv(id, value);
- };
-_type2uniformCommit[GL_BOOL_VEC4] = function (gl, id, value) {
- gl.uniform4iv(id, value);
- };
-_type2uniformCommit[GL_FLOAT_MAT2] = function (gl, id, value) {
- gl.uniformMatrix2fv(id, false, value);
- };
-_type2uniformCommit[GL_FLOAT_MAT3] = function (gl, id, value) {
- gl.uniformMatrix3fv(id, false, value);
- };
-_type2uniformCommit[GL_FLOAT_MAT4] = function (gl, id, value) {
- gl.uniformMatrix4fv(id, false, value);
- };
-_type2uniformCommit[GL_SAMPLER_2D] = function (gl, id, value) {
- gl.uniform1i(id, value);
- };
-_type2uniformCommit[GL_SAMPLER_CUBE] = function (gl, id, value) {
- gl.uniform1i(id, value);
- };
-
-/**
- * _type2uniformArrayCommit
- */
-var _type2uniformArrayCommit = {};
-_type2uniformArrayCommit[GL_INT] = function (gl, id, value) {
- gl.uniform1iv(id, value);
- };
-_type2uniformArrayCommit[GL_FLOAT$1] = function (gl, id, value) {
- gl.uniform1fv(id, value);
- };
-_type2uniformArrayCommit[GL_FLOAT_VEC2] = function (gl, id, value) {
- gl.uniform2fv(id, value);
- };
-_type2uniformArrayCommit[GL_FLOAT_VEC3] = function (gl, id, value) {
- gl.uniform3fv(id, value);
- };
-_type2uniformArrayCommit[GL_FLOAT_VEC4] = function (gl, id, value) {
- gl.uniform4fv(id, value);
- };
-_type2uniformArrayCommit[GL_INT_VEC2] = function (gl, id, value) {
- gl.uniform2iv(id, value);
- };
-_type2uniformArrayCommit[GL_INT_VEC3] = function (gl, id, value) {
- gl.uniform3iv(id, value);
- };
-_type2uniformArrayCommit[GL_INT_VEC4] = function (gl, id, value) {
- gl.uniform4iv(id, value);
- };
-_type2uniformArrayCommit[GL_BOOL] = function (gl, id, value) {
- gl.uniform1iv(id, value);
- };
-_type2uniformArrayCommit[GL_BOOL_VEC2] = function (gl, id, value) {
- gl.uniform2iv(id, value);
- };
-_type2uniformArrayCommit[GL_BOOL_VEC3] = function (gl, id, value) {
- gl.uniform3iv(id, value);
- };
-_type2uniformArrayCommit[GL_BOOL_VEC4] = function (gl, id, value) {
- gl.uniform4iv(id, value);
- };
-_type2uniformArrayCommit[GL_FLOAT_MAT2] = function (gl, id, value) {
- gl.uniformMatrix2fv(id, false, value);
- };
-_type2uniformArrayCommit[GL_FLOAT_MAT3] = function (gl, id, value) {
- gl.uniformMatrix3fv(id, false, value);
- };
-_type2uniformArrayCommit[GL_FLOAT_MAT4] = function (gl, id, value) {
- gl.uniformMatrix4fv(id, false, value);
- };
-_type2uniformArrayCommit[GL_SAMPLER_2D] = function (gl, id, value) {
- gl.uniform1iv(id, value);
- };
-_type2uniformArrayCommit[GL_SAMPLER_CUBE] = function (gl, id, value) {
- gl.uniform1iv(id, value);
- };
-
-/**
- * _commitBlendStates
- */
-function _commitBlendStates(gl, cur, next) {
- // enable/disable blend
- if (cur.blend !== next.blend) {
- if (!next.blend) {
- gl.disable(gl.BLEND);
- return;
- }
-
- gl.enable(gl.BLEND);
-
- if (
- next.blendSrc === enums$1.BLEND_CONSTANT_COLOR ||
- next.blendSrc === enums$1.BLEND_ONE_MINUS_CONSTANT_COLOR ||
- next.blendDst === enums$1.BLEND_CONSTANT_COLOR ||
- next.blendDst === enums$1.BLEND_ONE_MINUS_CONSTANT_COLOR
- ) {
- gl.blendColor(
- (next.blendColor >> 24) / 255,
- (next.blendColor >> 16 & 0xff) / 255,
- (next.blendColor >> 8 & 0xff) / 255,
- (next.blendColor & 0xff) / 255
- );
- }
-
- if (next.blendSep) {
- gl.blendFuncSeparate(next.blendSrc, next.blendDst, next.blendSrcAlpha, next.blendDstAlpha);
- gl.blendEquationSeparate(next.blendEq, next.blendAlphaEq);
- } else {
- gl.blendFunc(next.blendSrc, next.blendDst);
- gl.blendEquation(next.blendEq);
- }
-
- return;
- }
-
- // nothing to update
- if (next.blend === false) {
- return;
- }
-
- // blend-color
- if (cur.blendColor !== next.blendColor) {
- gl.blendColor(
- (next.blendColor >> 24) / 255,
- (next.blendColor >> 16 & 0xff) / 255,
- (next.blendColor >> 8 & 0xff) / 255,
- (next.blendColor & 0xff) / 255
- );
- }
-
- // separate diff, reset all
- if (cur.blendSep !== next.blendSep) {
- if (next.blendSep) {
- gl.blendFuncSeparate(next.blendSrc, next.blendDst, next.blendSrcAlpha, next.blendDstAlpha);
- gl.blendEquationSeparate(next.blendEq, next.blendAlphaEq);
- } else {
- gl.blendFunc(next.blendSrc, next.blendDst);
- gl.blendEquation(next.blendEq);
- }
-
- return;
- }
-
- if (next.blendSep) {
- // blend-func-separate
- if (
- cur.blendSrc !== next.blendSrc ||
- cur.blendDst !== next.blendDst ||
- cur.blendSrcAlpha !== next.blendSrcAlpha ||
- cur.blendDstAlpha !== next.blendDstAlpha
- ) {
- gl.blendFuncSeparate(next.blendSrc, next.blendDst, next.blendSrcAlpha, next.blendDstAlpha);
- }
-
- // blend-equation-separate
- if (
- cur.blendEq !== next.blendEq ||
- cur.blendAlphaEq !== next.blendAlphaEq
- ) {
- gl.blendEquationSeparate(next.blendEq, next.blendAlphaEq);
- }
- } else {
- // blend-func
- if (
- cur.blendSrc !== next.blendSrc ||
- cur.blendDst !== next.blendDst
- ) {
- gl.blendFunc(next.blendSrc, next.blendDst);
- }
-
- // blend-equation
- if (cur.blendEq !== next.blendEq) {
- gl.blendEquation(next.blendEq);
- }
- }
-}
-
-/**
- * _commitDepthStates
- */
-function _commitDepthStates(gl, cur, next) {
- // enable/disable depth-test
- if (cur.depthTest !== next.depthTest) {
- if (!next.depthTest) {
- gl.disable(gl.DEPTH_TEST);
- return;
- }
-
- gl.enable(gl.DEPTH_TEST);
- gl.depthFunc(next.depthFunc);
- gl.depthMask(next.depthWrite);
-
- return;
- }
-
- // commit depth-write
- if (cur.depthWrite !== next.depthWrite) {
- gl.depthMask(next.depthWrite);
- }
-
- // check if depth-write enabled
- if (next.depthTest === false) {
- if (next.depthWrite) {
- next.depthTest = true;
- next.depthFunc = enums$1.DS_FUNC_ALWAYS;
-
- gl.enable(gl.DEPTH_TEST);
- gl.depthFunc(next.depthFunc);
- }
-
- return;
- }
-
- // depth-func
- if (cur.depthFunc !== next.depthFunc) {
- gl.depthFunc(next.depthFunc);
- }
-}
-
-/**
- * _commitStencilStates
- */
-function _commitStencilStates(gl, cur, next) {
- if (next.stencilTest !== cur.stencilTest) {
- if (!next.stencilTest) {
- gl.disable(gl.STENCIL_TEST);
- return;
- }
-
- gl.enable(gl.STENCIL_TEST);
-
- if (next.stencilSep) {
- gl.stencilFuncSeparate(gl.FRONT, next.stencilFuncFront, next.stencilRefFront, next.stencilMaskFront);
- gl.stencilMaskSeparate(gl.FRONT, next.stencilWriteMaskFront);
- gl.stencilOpSeparate(gl.FRONT, next.stencilFailOpFront, next.stencilZFailOpFront, next.stencilZPassOpFront);
- gl.stencilFuncSeparate(gl.BACK, next.stencilFuncBack, next.stencilRefBack, next.stencilMaskBack);
- gl.stencilMaskSeparate(gl.BACK, next.stencilWriteMaskBack);
- gl.stencilOpSeparate(gl.BACK, next.stencilFailOpBack, next.stencilZFailOpBack, next.stencilZPassOpBack);
- } else {
- gl.stencilFunc(next.stencilFuncFront, next.stencilRefFront, next.stencilMaskFront);
- gl.stencilMask(next.stencilWriteMaskFront);
- gl.stencilOp(next.stencilFailOpFront, next.stencilZFailOpFront, next.stencilZPassOpFront);
- }
-
- return;
- }
-
- // fast return
- if (!next.stencilTest) {
- return;
- }
-
- if (cur.stencilSep !== next.stencilSep) {
- if (next.stencilSep) {
- gl.stencilFuncSeparate(gl.FRONT, next.stencilFuncFront, next.stencilRefFront, next.stencilMaskFront);
- gl.stencilMaskSeparate(gl.FRONT, next.stencilWriteMaskFront);
- gl.stencilOpSeparate(gl.FRONT, next.stencilFailOpFront, next.stencilZFailOpFront, next.stencilZPassOpFront);
- gl.stencilFuncSeparate(gl.BACK, next.stencilFuncBack, next.stencilRefBack, next.stencilMaskBack);
- gl.stencilMaskSeparate(gl.BACK, next.stencilWriteMaskBack);
- gl.stencilOpSeparate(gl.BACK, next.stencilFailOpBack, next.stencilZFailOpBack, next.stencilZPassOpBack);
- } else {
- gl.stencilFunc(next.stencilFuncFront, next.stencilRefFront, next.stencilMaskFront);
- gl.stencilMask(next.stencilWriteMaskFront);
- gl.stencilOp(next.stencilFailOpFront, next.stencilZFailOpFront, next.stencilZPassOpFront);
- }
- return;
- }
-
- if (next.stencilSep) {
- // front
- if (
- cur.stencilFuncFront !== next.stencilFuncFront ||
- cur.stencilRefFront !== next.stencilRefFront ||
- cur.stencilMaskFront !== next.stencilMaskFront
- ) {
- gl.stencilFuncSeparate(gl.FRONT, next.stencilFuncFront, next.stencilRefFront, next.stencilMaskFront);
- }
- if (cur.stencilWriteMaskFront !== next.stencilWriteMaskFront) {
- gl.stencilMaskSeparate(gl.FRONT, next.stencilWriteMaskFront);
- }
- if (
- cur.stencilFailOpFront !== next.stencilFailOpFront ||
- cur.stencilZFailOpFront !== next.stencilZFailOpFront ||
- cur.stencilZPassOpFront !== next.stencilZPassOpFront
- ) {
- gl.stencilOpSeparate(gl.FRONT, next.stencilFailOpFront, next.stencilZFailOpFront, next.stencilZPassOpFront);
- }
-
- // back
- if (
- cur.stencilFuncBack !== next.stencilFuncBack ||
- cur.stencilRefBack !== next.stencilRefBack ||
- cur.stencilMaskBack !== next.stencilMaskBack
- ) {
- gl.stencilFuncSeparate(gl.BACK, next.stencilFuncBack, next.stencilRefBack, next.stencilMaskBack);
- }
- if (cur.stencilWriteMaskBack !== next.stencilWriteMaskBack) {
- gl.stencilMaskSeparate(gl.BACK, next.stencilWriteMaskBack);
- }
- if (
- cur.stencilFailOpBack !== next.stencilFailOpBack ||
- cur.stencilZFailOpBack !== next.stencilZFailOpBack ||
- cur.stencilZPassOpBack !== next.stencilZPassOpBack
- ) {
- gl.stencilOpSeparate(gl.BACK, next.stencilFailOpBack, next.stencilZFailOpBack, next.stencilZPassOpBack);
- }
- } else {
- if (
- cur.stencilFuncFront !== next.stencilFuncFront ||
- cur.stencilRefFront !== next.stencilRefFront ||
- cur.stencilMaskFront !== next.stencilMaskFront
- ) {
- gl.stencilFunc(next.stencilFuncFront, next.stencilRefFront, next.stencilMaskFront);
- }
- if (cur.stencilWriteMaskFront !== next.stencilWriteMaskFront) {
- gl.stencilMask(next.stencilWriteMaskFront);
- }
- if (
- cur.stencilFailOpFront !== next.stencilFailOpFront ||
- cur.stencilZFailOpFront !== next.stencilZFailOpFront ||
- cur.stencilZPassOpFront !== next.stencilZPassOpFront
- ) {
- gl.stencilOp(next.stencilFailOpFront, next.stencilZFailOpFront, next.stencilZPassOpFront);
- }
- }
-
-}
-
-/**
- * _commitCullMode
- */
-function _commitCullMode(gl, cur, next) {
- if (cur.cullMode === next.cullMode) {
- return;
- }
-
- if (next.cullMode === enums$1.CULL_NONE) {
- gl.disable(gl.CULL_FACE);
- return;
- }
-
- gl.enable(gl.CULL_FACE);
- gl.cullFace(next.cullMode);
-}
-
-/**
- * _commitVertexBuffers
- */
-function _commitVertexBuffers(device, gl, cur, next) {
- var attrsDirty = false;
-
- // nothing changed for vertex buffer
- if (next.maxStream === -1) {
- console.warn('VertexBuffer not assigned, please call setVertexBuffer before every draw.');
- return;
- }
-
- if (cur.maxStream !== next.maxStream) {
- attrsDirty = true;
- } else if (cur.program !== next.program) {
- attrsDirty = true;
- } else {
- for (var i = 0; i < next.maxStream + 1; ++i) {
- if (
- cur.vertexBuffers[i] !== next.vertexBuffers[i] ||
- cur.vertexBufferOffsets[i] !== next.vertexBufferOffsets[i]
- ) {
- attrsDirty = true;
- break;
- }
- }
- }
-
- if (attrsDirty) {
- for (var i$1 = 0; i$1 < device._caps.maxVertexAttribs; ++i$1) {
- device._newAttributes[i$1] = 0;
- }
-
- for (var i$2 = 0; i$2 < next.maxStream + 1; ++i$2) {
- var vb = next.vertexBuffers[i$2];
- var vbOffset = next.vertexBufferOffsets[i$2];
- if (!vb) {
- continue;
- }
-
- gl.bindBuffer(gl.ARRAY_BUFFER, vb._glID);
-
- for (var j = 0; j < next.program._attributes.length; ++j) {
- var attr = next.program._attributes[j];
-
- var el = vb._format.element(attr.name);
- if (!el) {
- console.warn(("Can not find vertex attribute: " + (attr.name)));
- continue;
- }
-
- if (device._enabledAttributes[attr.location] === 0) {
- gl.enableVertexAttribArray(attr.location);
- device._enabledAttributes[attr.location] = 1;
- }
- device._newAttributes[attr.location] = 1;
-
- gl.vertexAttribPointer(
- attr.location,
- el.num,
- el.type,
- el.normalize,
- el.stride,
- el.offset + vbOffset * el.stride
- );
- }
- }
-
- // disable unused attributes
- for (var i$3 = 0; i$3 < device._caps.maxVertexAttribs; ++i$3) {
- if (device._enabledAttributes[i$3] !== device._newAttributes[i$3]) {
- gl.disableVertexAttribArray(i$3);
- device._enabledAttributes[i$3] = 0;
- }
- }
- }
-}
-
-/**
- * _commitTextures
- */
-function _commitTextures(gl, cur, next) {
- for (var i = 0; i < next.maxTextureSlot + 1; ++i) {
- if (cur.textureUnits[i] !== next.textureUnits[i]) {
- var texture = next.textureUnits[i];
- if (texture && texture._glID !== -1) {
- gl.activeTexture(gl.TEXTURE0 + i);
- gl.bindTexture(texture._target, texture._glID);
- }
- }
- }
-}
-
-/**
- * _attach
- */
-function _attach(gl, location, attachment, face) {
- if ( face === void 0 ) face = 0;
-
- if (attachment instanceof Texture2D) {
- gl.framebufferTexture2D(
- gl.FRAMEBUFFER,
- location,
- gl.TEXTURE_2D,
- attachment._glID,
- 0
- );
- } else if (attachment instanceof TextureCube) {
- gl.framebufferTexture2D(
- gl.FRAMEBUFFER,
- location,
- gl.TEXTURE_CUBE_MAP_POSITIVE_X + face,
- attachment._glID,
- 0
- );
- } else {
- gl.framebufferRenderbuffer(
- gl.FRAMEBUFFER,
- location,
- gl.RENDERBUFFER,
- attachment._glID
- );
- }
-}
-
-var Device = function Device(canvasEL, opts) {
- var this$1 = this;
-
- var gl;
-
- // default options
- opts = opts || {};
- if (opts.alpha === undefined) {
- opts.alpha = false;
- }
- if (opts.stencil === undefined) {
- opts.stencil = true;
- }
- if (opts.depth === undefined) {
- opts.depth = true;
- }
- if (opts.antialias === undefined) {
- opts.antialias = false;
- }
- // NOTE: it is said the performance improved in mobile device with this flag off.
- if (opts.preserveDrawingBuffer === undefined) {
- opts.preserveDrawingBuffer = false;
- }
-
- try {
- gl = canvasEL.getContext('webgl', opts)
- || canvasEL.getContext('experimental-webgl', opts)
- || canvasEL.getContext('webkit-3d', opts)
- || canvasEL.getContext('moz-webgl', opts);
- } catch (err) {
- console.error(err);
- return;
- }
-
- // statics
- this._gl = gl;
- this._extensions = {};
- this._caps = {}; // capability
- this._stats = {
- texture: 0,
- vb: 0,
- ib: 0,
- drawcalls: 0,
- };
-
- this._initExtensions([
- 'EXT_texture_filter_anisotropic',
- 'EXT_shader_texture_lod',
- 'OES_standard_derivatives',
- 'OES_texture_float',
- 'OES_texture_float_linear',
- 'OES_texture_half_float',
- 'OES_texture_half_float_linear',
- 'OES_vertex_array_object',
- 'WEBGL_compressed_texture_atc',
- 'WEBGL_compressed_texture_etc1',
- 'WEBGL_compressed_texture_pvrtc',
- 'WEBGL_compressed_texture_s3tc',
- 'WEBGL_depth_texture',
- 'WEBGL_draw_buffers' ]);
- this._initCaps();
- this._initStates();
-
- // runtime
- State.initDefault(this);
- this._current = new State(this);
- this._next = new State(this);
- this._uniforms = {}; // name: { value, num, dirty }
- this._vx = this._vy = this._vw = this._vh = 0;
- this._sx = this._sy = this._sw = this._sh = 0;
- this._framebuffer = null;
-
- //
- this._enabledAttributes = new Array(this._caps.maxVertexAttribs);
- this._newAttributes = new Array(this._caps.maxVertexAttribs);
-
- for (var i = 0; i < this._caps.maxVertexAttribs; ++i) {
- this$1._enabledAttributes[i] = 0;
- this$1._newAttributes[i] = 0;
- }
-};
-
-Device.prototype._initExtensions = function _initExtensions (extensions) {
- var this$1 = this;
-
- var gl = this._gl;
-
- for (var i = 0; i < extensions.length; ++i) {
- var name = extensions[i];
-
- var vendorPrefixes = ["", "WEBKIT_", "MOZ_"];
- for (var j = 0; j < vendorPrefixes.length; j++) {
- try {
- var ext = gl.getExtension(vendorPrefixes[j] + name);
- if (ext) {
- this$1._extensions[name] = ext;
- }
- } catch (e) {
- console.error(e);
- }
- }
- }
-};
-
-Device.prototype._initCaps = function _initCaps () {
- var gl = this._gl;
- var extDrawBuffers = this.ext('WEBGL_draw_buffers');
-
- this._caps.maxVertexStreams = 4;
- this._caps.maxVertexTextures = gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS);
- this._caps.maxFragUniforms = gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS);
- this._caps.maxTextureUnits = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
- this._caps.maxVertexAttribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
-
- this._caps.maxDrawBuffers = extDrawBuffers ? gl.getParameter(extDrawBuffers.MAX_DRAW_BUFFERS_WEBGL) : 1;
- this._caps.maxColorAttachments = extDrawBuffers ? gl.getParameter(extDrawBuffers.MAX_COLOR_ATTACHMENTS_WEBGL) : 1;
-};
-
-Device.prototype._initStates = function _initStates () {
- var gl = this._gl;
-
- // gl.frontFace(gl.CCW);
- gl.disable(gl.BLEND);
- gl.blendFunc(gl.ONE, gl.ZERO);
- gl.blendEquation(gl.FUNC_ADD);
- gl.blendColor(1,1,1,1);
-
- gl.colorMask(true, true, true, true);
-
- gl.enable(gl.CULL_FACE);
- gl.cullFace(gl.BACK);
-
- gl.disable(gl.DEPTH_TEST);
- gl.depthFunc(gl.LESS);
- gl.depthMask(false);
- gl.disable(gl.POLYGON_OFFSET_FILL);
- gl.depthRange(0,1);
-
- gl.disable(gl.STENCIL_TEST);
- gl.stencilFunc(gl.ALWAYS, 0, 0xFF);
- gl.stencilMask(0xFF);
- gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
-
- // TODO:
- // this.setAlphaToCoverage(false);
- // this.setTransformFeedbackBuffer(null);
- // this.setRaster(true);
- // this.setDepthBias(false);
-
- gl.clearDepth(1);
- gl.clearColor(0, 0, 0, 0);
- gl.clearStencil(0);
-
- gl.disable(gl.SCISSOR_TEST);
-};
-
-Device.prototype._restoreTexture = function _restoreTexture (unit) {
- var gl = this._gl;
-
- var texture = this._current.textureUnits[unit];
- if (texture && texture._glID !== -1) {
- gl.bindTexture(texture._target, texture._glID);
- } else {
- gl.bindTexture(gl.TEXTURE_2D, null);
- }
-};
-
-Device.prototype._restoreIndexBuffer = function _restoreIndexBuffer () {
- var gl = this._gl;
-
- var ib = this._current.indexBuffer;
- if (ib && ib._glID !== -1) {
- gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ib._glID);
- }
- else {
- gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
- }
-};
-
-/**
- * @method ext
- * @param {string} name
- */
-Device.prototype.ext = function ext (name) {
- return this._extensions[name];
-};
-
-// ===============================
-// Immediate Settings
-// ===============================
-
-/**
- * @method setFrameBuffer
- * @param {FrameBuffer} fb - null means use the backbuffer
- */
-Device.prototype.setFrameBuffer = function setFrameBuffer (fb) {
- var this$1 = this;
-
- if (this._framebuffer === fb) {
- return;
- }
-
- this._framebuffer = fb;
- var gl = this._gl;
-
- if (fb === null) {
- gl.bindFramebuffer(gl.FRAMEBUFFER, null);
- return;
- }
-
- gl.bindFramebuffer(gl.FRAMEBUFFER, fb._glID);
-
- var numColors = this._framebuffer._colors.length;
- for (var i = 0; i < numColors; ++i) {
- var colorBuffer = this$1._framebuffer._colors[i];
- _attach(gl, gl.COLOR_ATTACHMENT0 + i, colorBuffer);
-
- // TODO: what about cubemap face??? should be the target parameter for colorBuffer
- }
- for (var i$1 = numColors; i$1 < this._caps.maxColorAttachments; ++i$1) {
- gl.framebufferTexture2D(
- gl.FRAMEBUFFER,
- gl.COLOR_ATTACHMENT0 + i$1,
- gl.TEXTURE_2D,
- null,
- 0
- );
- }
-
- if (this._framebuffer._depth) {
- _attach(gl, gl.DEPTH_ATTACHMENT, this._framebuffer._depth);
- }
-
- if (this._framebuffer._stencil) {
- _attach(gl, gl.STENCIL_ATTACHMENT, fb._stencil);
- }
-
- if (this._framebuffer._depthStencil) {
- _attach(gl, gl.DEPTH_STENCIL_ATTACHMENT, fb._depthStencil);
- }
-};
-
-/**
- * @method setViewport
- * @param {Number} x
- * @param {Number} y
- * @param {Number} w
- * @param {Number} h
- */
-Device.prototype.setViewport = function setViewport (x, y, w, h) {
- if (
- this._vx !== x ||
- this._vy !== y ||
- this._vw !== w ||
- this._vh !== h
- ) {
- this._gl.viewport(x, y, w, h);
- this._vx = x;
- this._vy = y;
- this._vw = w;
- this._vh = h;
- }
-};
-
-/**
- * @method setScissor
- * @param {Number} x
- * @param {Number} y
- * @param {Number} w
- * @param {Number} h
- */
-Device.prototype.setScissor = function setScissor (x, y, w, h) {
- if (
- this._sx !== x ||
- this._sy !== y ||
- this._sw !== w ||
- this._sh !== h
- ) {
- this._gl.scissor(x, y, w, h);
- this._sx = x;
- this._sy = y;
- this._sw = w;
- this._sh = h;
- }
-};
-
-/**
- * @method clear
- * @param {Object} opts
- * @param {Array} opts.color
- * @param {Number} opts.depth
- * @param {Number} opts.stencil
- */
-Device.prototype.clear = function clear (opts) {
- var gl = this._gl;
- var flags = 0;
-
- if (opts.color !== undefined) {
- flags |= gl.COLOR_BUFFER_BIT;
- gl.clearColor(opts.color[0], opts.color[1], opts.color[2], opts.color[3]);
- }
-
- if (opts.depth !== undefined) {
- flags |= gl.DEPTH_BUFFER_BIT;
- gl.clearDepth(opts.depth);
-
- gl.enable(gl.DEPTH_TEST);
- gl.depthMask(true);
- gl.depthFunc(gl.ALWAYS);
- }
-
- if (opts.stencil !== undefined) {
- flags |= gl.STENCIL_BUFFER_BIT;
- gl.clearStencil(opts.stencil);
- }
-
- gl.clear(flags);
-
- // restore depth-write
- if (opts.depth !== undefined) {
- if (this._current.depthTest === false) {
- gl.disable(gl.DEPTH_TEST);
- } else {
- if (this._current.depthWrite === false) {
- gl.depthMask(false);
- }
- if (this._current.depthFunc !== enums$1.DS_FUNC_ALWAYS) {
- gl.depthFunc(this._current.depthFunc);
- }
- }
- }
-};
-
-// ===============================
-// Deferred States
-// ===============================
-
-/**
- * @method enableBlend
- */
-Device.prototype.enableBlend = function enableBlend () {
- this._next.blend = true;
-};
-
-/**
- * @method enableDepthTest
- */
-Device.prototype.enableDepthTest = function enableDepthTest () {
- this._next.depthTest = true;
-};
-
-/**
- * @method enableDepthWrite
- */
-Device.prototype.enableDepthWrite = function enableDepthWrite () {
- this._next.depthWrite = true;
-};
-
-/**
- * @method enableStencilTest
- */
-Device.prototype.enableStencilTest = function enableStencilTest () {
- this._next.stencilTest = true;
-};
-
-/**
- * @method setStencilFunc
- * @param {DS_FUNC_*} func
- * @param {Number} ref
- * @param {Number} mask
- */
-Device.prototype.setStencilFunc = function setStencilFunc (func, ref, mask) {
- this._next.stencilSep = false;
- this._next.stencilFuncFront = this._next.stencilFuncBack = func;
- this._next.stencilRefFront = this._next.stencilRefBack = ref;
- this._next.stencilMaskFront = this._next.stencilMaskBack = mask;
-};
-
-/**
- * @method setStencilFuncFront
- * @param {DS_FUNC_*} func
- * @param {Number} ref
- * @param {Number} mask
- */
-Device.prototype.setStencilFuncFront = function setStencilFuncFront (func, ref, mask) {
- this._next.stencilSep = true;
- this._next.stencilFuncFront = func;
- this._next.stencilRefFront = ref;
- this._next.stencilMaskFront = mask;
-};
-
-/**
- * @method setStencilFuncBack
- * @param {DS_FUNC_*} func
- * @param {Number} ref
- * @param {Number} mask
- */
-Device.prototype.setStencilFuncBack = function setStencilFuncBack (func, ref, mask) {
- this._next.stencilSep = true;
- this._next.stencilFuncBack = func;
- this._next.stencilRefBack = ref;
- this._next.stencilMaskBack = mask;
-};
-
-/**
- * @method setStencilOp
- * @param {STENCIL_OP_*} failOp
- * @param {STENCIL_OP_*} zFailOp
- * @param {STENCIL_OP_*} zPassOp
- * @param {Number} writeMask
- */
-Device.prototype.setStencilOp = function setStencilOp (failOp, zFailOp, zPassOp, writeMask) {
- this._next.stencilFailOpFront = this._next.stencilFailOpBack = failOp;
- this._next.stencilZFailOpFront = this._next.stencilZFailOpBack = zFailOp;
- this._next.stencilZPassOpFront = this._next.stencilZPassOpBack = zPassOp;
- this._next.stencilWriteMaskFront = this._next.stencilWriteMaskBack = writeMask;
-};
-
-/**
- * @method setStencilOpFront
- * @param {STENCIL_OP_*} failOp
- * @param {STENCIL_OP_*} zFailOp
- * @param {STENCIL_OP_*} zPassOp
- * @param {Number} writeMask
- */
-Device.prototype.setStencilOpFront = function setStencilOpFront (failOp, zFailOp, zPassOp, writeMask) {
- this._next.stencilSep = true;
- this._next.stencilFailOpFront = failOp;
- this._next.stencilZFailOpFront = zFailOp;
- this._next.stencilZPassOpFront = zPassOp;
- this._next.stencilWriteMaskFront = writeMask;
-};
-
-/**
- * @method setStencilOpBack
- * @param {STENCIL_OP_*} failOp
- * @param {STENCIL_OP_*} zFailOp
- * @param {STENCIL_OP_*} zPassOp
- * @param {Number} writeMask
- */
-Device.prototype.setStencilOpBack = function setStencilOpBack (failOp, zFailOp, zPassOp, writeMask) {
- this._next.stencilSep = true;
- this._next.stencilFailOpBack = failOp;
- this._next.stencilZFailOpBack = zFailOp;
- this._next.stencilZPassOpBack = zPassOp;
- this._next.stencilWriteMaskBack = writeMask;
-};
-
-/**
- * @method setDepthFunc
- * @param {DS_FUNC_*} depthFunc
- */
-Device.prototype.setDepthFunc = function setDepthFunc (depthFunc) {
- this._next.depthFunc = depthFunc;
-};
-
-/**
- * @method setBlendColor32
- * @param {Number} rgba
- */
-Device.prototype.setBlendColor32 = function setBlendColor32 (rgba) {
- this._next.blendColor = rgba;
-};
-
-/**
- * @method setBlendColor
- * @param {Number} r
- * @param {Number} g
- * @param {Number} b
- * @param {Number} a
- */
-Device.prototype.setBlendColor = function setBlendColor (r, g, b, a) {
- this._next.blendColor = ((r * 255) << 24 | (g * 255) << 16 | (b * 255) << 8 | a * 255) >>> 0;
-};
-
-/**
- * @method setBlendFunc
- * @param {BELND_*} src
- * @param {BELND_*} dst
- */
-Device.prototype.setBlendFunc = function setBlendFunc (src, dst) {
- this._next.blendSep = false;
- this._next.blendSrc = src;
- this._next.blendDst = dst;
-};
-
-/**
- * @method setBlendFuncSep
- * @param {BELND_*} src
- * @param {BELND_*} dst
- * @param {BELND_*} srcAlpha
- * @param {BELND_*} dstAlpha
- */
-Device.prototype.setBlendFuncSep = function setBlendFuncSep (src, dst, srcAlpha, dstAlpha) {
- this._next.blendSep = true;
- this._next.blendSrc = src;
- this._next.blendDst = dst;
- this._next.blendSrcAlpha = srcAlpha;
- this._next.blendDstAlpha = dstAlpha;
-};
-
-/**
- * @method setBlendEq
- * @param {BELND_FUNC_*} eq
- */
-Device.prototype.setBlendEq = function setBlendEq (eq) {
- this._next.blendSep = false;
- this._next.blendEq = eq;
-};
-
-/**
- * @method setBlendEqSep
- * @param {BELND_FUNC_*} eq
- * @param {BELND_FUNC_*} alphaEq
- */
-Device.prototype.setBlendEqSep = function setBlendEqSep (eq, alphaEq) {
- this._next.blendSep = true;
- this._next.blendEq = eq;
- this._next.blendAlphaEq = alphaEq;
-};
-
-/**
- * @method setCullMode
- * @param {CULL_*} mode
- */
-Device.prototype.setCullMode = function setCullMode (mode) {
- this._next.cullMode = mode;
-};
-
-/**
- * @method setVertexBuffer
- * @param {Number} stream
- * @param {VertexBuffer} buffer
- * @param {Number} start - start vertex
- */
-Device.prototype.setVertexBuffer = function setVertexBuffer (stream, buffer, start) {
- if ( start === void 0 ) start = 0;
-
- this._next.vertexBuffers[stream] = buffer;
- this._next.vertexBufferOffsets[stream] = start;
- if (this._next.maxStream < stream) {
- this._next.maxStream = stream;
- }
-};
-
-/**
- * @method setIndexBuffer
- * @param {IndexBuffer} buffer
- */
-Device.prototype.setIndexBuffer = function setIndexBuffer (buffer) {
- this._next.indexBuffer = buffer;
-};
-
-/**
- * @method setProgram
- * @param {Program} program
- */
-Device.prototype.setProgram = function setProgram (program) {
- this._next.program = program;
-};
-
-/**
- * @method setTexture
- * @param {String} name
- * @param {Texture} texture
- * @param {Number} slot
- */
-Device.prototype.setTexture = function setTexture (name, texture, slot) {
- if (slot >= this._caps.maxTextureUnits) {
- console.warn(("Can not set texture " + name + " at stage " + slot + ", max texture exceed: " + (this._caps.maxTextureUnits)));
- return;
- }
-
- this._next.textureUnits[slot] = texture;
- this.setUniform(name, slot);
-
- if (this._next.maxTextureSlot < slot) {
- this._next.maxTextureSlot = slot;
- }
-};
-
-/**
- * @method setTextureArray
- * @param {String} name
- * @param {Array} textures
- * @param {Int32Array} slots
- */
-Device.prototype.setTextureArray = function setTextureArray (name, textures, slots) {
- var this$1 = this;
-
- var len = textures.length;
- if (len >= this._caps.maxTextureUnits) {
- console.warn(("Can not set " + len + " textures for " + name + ", max texture exceed: " + (this._caps.maxTextureUnits)));
- return;
- }
- for (var i = 0; i < len; ++i) {
- var slot = slots[i];
- this$1._next.textureUnits[slot] = textures[i];
- }
- this.setUniform(name, slots);
-};
-
-/**
- * @method setUniform
- * @param {String} name
- * @param {*} value
- */
-Device.prototype.setUniform = function setUniform (name, value) {
- var uniform = this._uniforms[name];
- if (!uniform || (uniform.isArray && uniform.value.length < value.length)) {
- var newValue = value;
- var isArray = false;
- if (value instanceof Float32Array || Array.isArray(value)) {
- newValue = new Float32Array(value);
- isArray = true;
- }
- else if (value instanceof Int32Array) {
- newValue = new Int32Array(value);
- isArray = true;
- }
-
- uniform = {
- dirty: true,
- value: newValue,
- isArray: isArray
- };
- } else {
- var oldValue = uniform.value;
- var dirty = false;
- if (uniform.isArray) {
- for (var i = 0, l = oldValue.length; i < l; i++) {
- if (oldValue[i] !== value[i]) {
- dirty = true;
- oldValue[i] = value[i];
- }
- }
- }
- else {
- if (oldValue !== value) {
- dirty = true;
- uniform.value = value;
- }
- }
-
- if (dirty) {
- uniform.dirty = true;
- }
- }
- this._uniforms[name] = uniform;
-};
-
-/**
- * @method setPrimitiveType
- * @param {PT_*} type
- */
-Device.prototype.setPrimitiveType = function setPrimitiveType (type) {
- this._next.primitiveType = type;
-};
-
-/**
- * @method draw
- * @param {Number} base
- * @param {Number} count
- */
-Device.prototype.draw = function draw (base, count) {
- var this$1 = this;
-
- var gl = this._gl;
- var cur = this._current;
- var next = this._next;
-
- // commit blend
- _commitBlendStates(gl, cur, next);
-
- // commit depth
- _commitDepthStates(gl, cur, next);
-
- // commit stencil
- _commitStencilStates(gl, cur, next);
-
- // commit cull
- _commitCullMode(gl, cur, next);
-
- // commit vertex-buffer
- _commitVertexBuffers(this, gl, cur, next);
-
- // commit index-buffer
- if (cur.indexBuffer !== next.indexBuffer) {
- gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, next.indexBuffer ? next.indexBuffer._glID : null);
- }
-
- // commit program
- var programDirty = false;
- if (cur.program !== next.program) {
- if (next.program._linked) {
- gl.useProgram(next.program._glID);
- } else {
- console.warn('Failed to use program: has not linked yet.');
- }
- programDirty = true;
- }
-
- // commit texture/sampler
- _commitTextures(gl, cur, next);
-
- // commit uniforms
- for (var i = 0; i < next.program._uniforms.length; ++i) {
- var uniformInfo = next.program._uniforms[i];
- var uniform = this$1._uniforms[uniformInfo.name];
- if (!uniform) {
- // console.warn(`Can not find uniform ${uniformInfo.name}`);
- continue;
- }
-
- if (!programDirty && !uniform.dirty) {
- continue;
- }
-
- uniform.dirty = false;
-
- // TODO: please consider array uniform: uniformInfo.size > 0
-
- var commitFunc = (uniformInfo.size === undefined) ? _type2uniformCommit[uniformInfo.type] : _type2uniformArrayCommit[uniformInfo.type];
- if (!commitFunc) {
- console.warn(("Can not find commit function for uniform " + (uniformInfo.name)));
- continue;
- }
-
- commitFunc(gl, uniformInfo.location, uniform.value);
- }
-
- // drawPrimitives
- if (next.indexBuffer) {
- gl.drawElements(
- this._next.primitiveType,
- count,
- next.indexBuffer._format,
- base * next.indexBuffer._bytesPerIndex
- );
- } else {
- gl.drawArrays(
- this._next.primitiveType,
- base,
- count
- );
- }
-
- // TODO: autogen mipmap for color buffer
- // if (this._framebuffer && this._framebuffer.colors[0].mipmap) {
- // gl.bindTexture(this._framebuffer.colors[i]._target, colors[i]._glID);
- // gl.generateMipmap(this._framebuffer.colors[i]._target);
- // }
-
- // update stats
- this._stats.drawcalls += 1;
-
- // reset states
- cur.set(next);
- next.reset();
-};
-
-var gfx = {
- // classes
- VertexFormat: VertexFormat,
- IndexBuffer: IndexBuffer,
- VertexBuffer: VertexBuffer,
- Program: Program,
- Texture: Texture,
- Texture2D: Texture2D,
- TextureCube: TextureCube,
- RenderBuffer: RenderBuffer,
- FrameBuffer: FrameBuffer,
- Device: Device,
-
- // functions
- attrTypeBytes: attrTypeBytes,
- glFilter: glFilter,
- glTextureFmt: glTextureFmt,
-};
-Object.assign(gfx, enums$1);
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var InputAssembler = function InputAssembler(vb, ib, pt) {
- if ( pt === void 0 ) pt = gfx.PT_TRIANGLES;
-
- this._vertexBuffer = vb;
- this._indexBuffer = ib;
- this._primitiveType = pt;
- this._start = 0;
- this._count = -1;
-
- // TODO: instancing data
- // this._stream = 0;
-};
-
-InputAssembler.prototype.getPrimitiveCount = function getPrimitiveCount () {
- if (this._count !== -1) {
- return this._count;
- }
-
- if (this._indexBuffer) {
- return this._indexBuffer.count;
- }
-
- return this._vertexBuffer.count;
-};
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var Pass = function Pass(name) {
- this._programName = name;
-
- // cullmode
- this._cullMode = gfx.CULL_BACK;
-
- // blending
- this._blend = false;
- this._blendEq = gfx.BLEND_FUNC_ADD;
- this._blendAlphaEq = gfx.BLEND_FUNC_ADD;
- this._blendSrc = gfx.BLEND_ONE;
- this._blendDst = gfx.BLEND_ZERO;
- this._blendSrcAlpha = gfx.BLEND_ONE;
- this._blendDstAlpha = gfx.BLEND_ZERO;
- this._blendColor = 0xffffffff;
-
- // depth
- this._depthTest = false;
- this._depthWrite = false;
- this._depthFunc = gfx.DS_FUNC_LESS, this._stencilTest = false;
- // front
- this._stencilFuncFront = gfx.DS_FUNC_ALWAYS;
- this._stencilRefFront = 0;
- this._stencilMaskFront = 0xff;
- this._stencilFailOpFront = gfx.STENCIL_OP_KEEP;
- this._stencilZFailOpFront = gfx.STENCIL_OP_KEEP;
- this._stencilZPassOpFront = gfx.STENCIL_OP_KEEP;
- this._stencilWriteMaskFront = 0xff;
- // back
- this._stencilFuncBack = gfx.DS_FUNC_ALWAYS;
- this._stencilRefBack = 0;
- this._stencilMaskBack = 0xff;
- this._stencilFailOpBack = gfx.STENCIL_OP_KEEP;
- this._stencilZFailOpBack = gfx.STENCIL_OP_KEEP;
- this._stencilZPassOpBack = gfx.STENCIL_OP_KEEP;
- this._stencilWriteMaskBack = 0xff;
-};
-
-Pass.prototype.setCullMode = function setCullMode (cullMode) {
- this._cullMode = cullMode;
-};
-
-Pass.prototype.setBlend = function setBlend (
- blendEq,
- blendSrc,
- blendDst,
- blendAlphaEq,
- blendSrcAlpha,
- blendDstAlpha,
- blendColor
-) {
- if ( blendEq === void 0 ) blendEq = gfx.BLEND_FUNC_ADD;
- if ( blendSrc === void 0 ) blendSrc = gfx.BLEND_ONE;
- if ( blendDst === void 0 ) blendDst = gfx.BLEND_ZERO;
- if ( blendAlphaEq === void 0 ) blendAlphaEq = gfx.BLEND_FUNC_ADD;
- if ( blendSrcAlpha === void 0 ) blendSrcAlpha = gfx.BLEND_ONE;
- if ( blendDstAlpha === void 0 ) blendDstAlpha = gfx.BLEND_ZERO;
- if ( blendColor === void 0 ) blendColor = 0xffffffff;
-
- this._blend = true;
- this._blendEq = blendEq;
- this._blendSrc = blendSrc;
- this._blendDst = blendDst;
- this._blendAlphaEq = blendAlphaEq;
- this._blendSrcAlpha = blendSrcAlpha;
- this._blendDstAlpha = blendDstAlpha;
- this._blendColor = blendColor;
-};
-
-Pass.prototype.setDepth = function setDepth (
- depthTest,
- depthWrite,
- depthFunc
-) {
- if ( depthTest === void 0 ) depthTest = false;
- if ( depthWrite === void 0 ) depthWrite = false;
- if ( depthFunc === void 0 ) depthFunc = gfx.DS_FUNC_LESS;
-
- this._depthTest = depthTest;
- this._depthWrite = depthWrite;
- this._depthFunc = depthFunc;
-};
-
-Pass.prototype.setStencilFront = function setStencilFront (
- stencilFunc,
- stencilRef,
- stencilMask,
- stencilFailOp,
- stencilZFailOp,
- stencilZPassOp,
- stencilWriteMask
-) {
- if ( stencilFunc === void 0 ) stencilFunc = gfx.DS_FUNC_ALWAYS;
- if ( stencilRef === void 0 ) stencilRef = 0;
- if ( stencilMask === void 0 ) stencilMask = 0xff;
- if ( stencilFailOp === void 0 ) stencilFailOp = gfx.STENCIL_OP_KEEP;
- if ( stencilZFailOp === void 0 ) stencilZFailOp = gfx.STENCIL_OP_KEEP;
- if ( stencilZPassOp === void 0 ) stencilZPassOp = gfx.STENCIL_OP_KEEP;
- if ( stencilWriteMask === void 0 ) stencilWriteMask = 0xff;
-
- this._stencilTest = true;
- this._stencilFuncFront = stencilFunc;
- this._stencilRefFront = stencilRef;
- this._stencilMaskFront = stencilMask;
- this._stencilFailOpFront = stencilFailOp;
- this._stencilZFailOpFront = stencilZFailOp;
- this._stencilZPassOpFront = stencilZPassOp;
- this._stencilWriteMaskFront = stencilWriteMask;
-};
-
-Pass.prototype.setStencilBack = function setStencilBack (
- stencilFunc,
- stencilRef,
- stencilMask,
- stencilFailOp,
- stencilZFailOp,
- stencilZPassOp,
- stencilWriteMask
-) {
- if ( stencilFunc === void 0 ) stencilFunc = gfx.DS_FUNC_ALWAYS;
- if ( stencilRef === void 0 ) stencilRef = 0;
- if ( stencilMask === void 0 ) stencilMask = 0xff;
- if ( stencilFailOp === void 0 ) stencilFailOp = gfx.STENCIL_OP_KEEP;
- if ( stencilZFailOp === void 0 ) stencilZFailOp = gfx.STENCIL_OP_KEEP;
- if ( stencilZPassOp === void 0 ) stencilZPassOp = gfx.STENCIL_OP_KEEP;
- if ( stencilWriteMask === void 0 ) stencilWriteMask = 0xff;
-
- this._stencilTest = true;
- this._stencilFuncBack = stencilFunc;
- this._stencilRefBack = stencilRef;
- this._stencilMaskBack = stencilMask;
- this._stencilFailOpBack = stencilFailOp;
- this._stencilZFailOpBack = stencilZFailOp;
- this._stencilZPassOpBack = stencilZPassOp;
- this._stencilWriteMaskBack = stencilWriteMask;
-};
-
-Pass.prototype.disableStencilTest = function disableStencilTest () {
- this._stencilTest = false;
-};
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var _stageOffset = 0;
-var _name2stageID = {};
-
-var config = {
- addStage: function (name) {
- // already added
- if (_name2stageID[name] !== undefined) {
- return;
- }
-
- var stageID = 1 << _stageOffset;
- _name2stageID[name] = stageID;
-
- _stageOffset += 1;
- },
-
- stageID: function (name) {
- var id = _name2stageID[name];
- if (id === undefined) {
- return -1;
- }
- return id;
- },
-
- stageIDs: function (nameList) {
- var key = 0;
- for (var i = 0; i < nameList.length; ++i) {
- var id = _name2stageID[nameList[i]];
- if (id !== undefined) {
- key |= id;
- }
- }
- return key;
- }
-};
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var _genID$1 = 0;
-
-var Technique = function Technique(stages, parameters, passes, layer) {
- if ( layer === void 0 ) layer = 0;
-
- this._id = _genID$1++;
- this._stageIDs = config.stageIDs(stages);
- this._parameters = parameters; // {name, type, size, val}
- this._passes = passes;
- this._layer = layer;
- // TODO: this._version = 'webgl' or 'webgl2' // ????
-};
-
-var prototypeAccessors$3 = { passes: { configurable: true },stageIDs: { configurable: true } };
-
-Technique.prototype.setStages = function setStages (stages) {
- this._stageIDs = config.stageIDs(stages);
-};
-
-prototypeAccessors$3.passes.get = function () {
- return this._passes;
-};
-
-prototypeAccessors$3.stageIDs.get = function () {
- return this._stageIDs;
-};
-
-Object.defineProperties( Technique.prototype, prototypeAccessors$3 );
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var Effect = function Effect(techniques, properties, defines) {
- if ( properties === void 0 ) properties = {};
- if ( defines === void 0 ) defines = [];
-
- this._techniques = techniques;
- this._properties = properties;
- this._defines = defines;
-
- // TODO: check if params is valid for current technique???
-};
-
-Effect.prototype.clear = function clear () {
- this._techniques.length = 0;
- this._properties = null;
- this._defines.length = 0;
-};
-
-Effect.prototype.getTechnique = function getTechnique (stage) {
- var this$1 = this;
-
- var stageID = config.stageID(stage);
- for (var i = 0; i < this._techniques.length; ++i) {
- var tech = this$1._techniques[i];
- if (tech.stageIDs & stageID) {
- return tech;
- }
- }
-
- return null;
-};
-
-Effect.prototype.getProperty = function getProperty (name) {
- return this._properties[name];
-};
-
-Effect.prototype.setProperty = function setProperty (name, value) {
- // TODO: check if params is valid for current technique???
- this._properties[name] = value;
-};
-
-Effect.prototype.getDefine = function getDefine (name) {
- var this$1 = this;
-
- for (var i = 0; i < this._defines.length; ++i) {
- var def = this$1._defines[i];
- if ( def.name === name ) {
- return def.value;
- }
- }
-
- console.warn(("Failed to get define " + name + ", define not found."));
- return null;
-};
-
-Effect.prototype.define = function define (name, value) {
- var this$1 = this;
-
- for (var i = 0; i < this._defines.length; ++i) {
- var def = this$1._defines[i];
- if ( def.name === name ) {
- def.value = value;
- return;
- }
- }
-
- console.warn(("Failed to set define " + name + ", define not found."));
-};
-
-Effect.prototype.extractDefines = function extractDefines (out) {
- var this$1 = this;
- if ( out === void 0 ) out = {};
-
- for (var i = 0; i < this._defines.length; ++i) {
- var def = this$1._defines[i];
- out[def.name] = def.value;
- }
-
- return out;
-};
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-/**
- * @param {object} json
- */
-
-
-/**
- * @param {gfx.Device} device
- * @param {Object} data
- */
-function createIA(device, data) {
- if (!data.positions) {
- console.error('The data must have positions field');
- return null;
- }
-
- var verts = [];
- var vcount = data.positions.length / 3;
-
- for (var i = 0; i < vcount; ++i) {
- verts.push(data.positions[3 * i], data.positions[3 * i + 1], data.positions[3 * i + 2]);
-
- if (data.normals) {
- verts.push(data.normals[3 * i], data.normals[3 * i + 1], data.normals[3 * i + 2]);
- }
-
- if (data.uvs) {
- verts.push(data.uvs[2 * i], data.uvs[2 * i + 1]);
- }
- }
-
- var vfmt = [];
- vfmt.push({ name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 3 });
- if (data.normals) {
- vfmt.push({ name: gfx.ATTR_NORMAL, type: gfx.ATTR_TYPE_FLOAT32, num: 3 });
- }
- if (data.uvs) {
- vfmt.push({ name: gfx.ATTR_UV0, type: gfx.ATTR_TYPE_FLOAT32, num: 2 });
- }
-
- var vb = new gfx.VertexBuffer(
- device,
- new gfx.VertexFormat(vfmt),
- gfx.USAGE_STATIC,
- new Float32Array(verts),
- vcount
- );
-
- var ib = null;
- if (data.indices) {
- ib = new gfx.IndexBuffer(
- device,
- gfx.INDEX_FMT_UINT16,
- gfx.USAGE_STATIC,
- new Uint16Array(data.indices),
- data.indices.length
- );
- }
-
- return new InputAssembler(vb, ib);
-}
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var _m4_tmp = mat4.create();
-var _genID$2 = 0;
-
-var View = function View() {
- this._id = _genID$2++;
-
- // viewport
- this._rect = {
- x: 0, y: 0, w: 1, h: 1
- };
-
- // TODO:
- // this._scissor = {
- // x: 0, y: 0, w: 1, h: 1
- // };
-
- // clear options
- this._color = color4.new(0.3, 0.3, 0.3, 1);
- this._depth = 1;
- this._stencil = 0;
- this._clearFlags = enums.CLEAR_COLOR | enums.CLEAR_DEPTH;
-
- // matrix
- this._matView = mat4.create();
- this._matProj = mat4.create();
- this._matViewProj = mat4.create();
- this._matInvViewProj = mat4.create();
-
- // stages & framebuffer
- this._stages = [];
- this._cullingMask = 1;
- this._framebuffer = null;
-
- this._shadowLight = null; // TODO: should not refer light in view.
-};
-
-View.prototype.getForward = function getForward (out) {
- return vec3.set(
- out,
- -this._matView.m02,
- -this._matView.m06,
- -this._matView.m10
- );
-};
-
-View.prototype.getPosition = function getPosition (out) {
- mat4.invert(_m4_tmp, this._matView);
- return mat4.getTranslation(out, _m4_tmp);
-};
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var _forward = vec3.new(0, 0, -1);
-
-var _m4_tmp$1 = mat4.create();
-var _m3_tmp = mat3.create();
-var _transformedLightDirection = vec3.create();
-
-// compute light viewProjMat for shadow.
-function _computeSpotLightViewProjMatrix(light, outView, outProj) {
- // view matrix
- light._node.getWorldRT(outView);
- mat4.invert(outView, outView);
-
- // proj matrix
- mat4.perspective(outProj, light._spotAngle * light._spotAngleScale, 1, light._shadowMinDepth, light._shadowMaxDepth);
-}
-
-function _computeDirectionalLightViewProjMatrix(light, outView, outProj) {
- // view matrix
- light._node.getWorldRT(outView);
- mat4.invert(outView, outView);
-
- // TODO: should compute directional light frustum based on rendered meshes in scene.
- // proj matrix
- var halfSize = light._shadowFustumSize / 2;
- mat4.ortho(outProj, -halfSize, halfSize, -halfSize, halfSize, light._shadowMinDepth, light._shadowMaxDepth);
-}
-
-function _computePointLightViewProjMatrix(light, outView, outProj) {
- // TODO:
-}
-
-var Light = function Light() {
- this._poolID = -1;
- this._node = null;
-
- this._type = enums.LIGHT_DIRECTIONAL;
-
- this._color = color3.new(1, 1, 1);
- this._intensity = 1;
-
- // used for spot and point light
- this._range = 1;
- // used for spot light, default to 60 degrees
- this._spotAngle = toRadian(60);
- this._spotExp = 1;
- // cached for uniform
- this._directionUniform = new Float32Array(3);
- this._positionUniform = new Float32Array(3);
- this._colorUniform = new Float32Array([this._color.r * this._intensity, this._color.g * this._intensity, this._color.b * this._intensity]);
- this._spotUniform = new Float32Array([Math.cos(this._spotAngle * 0.5), this._spotExp]);
-
- // shadow params
- this._shadowType = enums.SHADOW_NONE;
- this._shadowFrameBuffer = null;
- this._shadowMap = null;
- this._shadowMapDirty = false;
- this._shadowDepthBuffer = null;
- this._shadowResolution = 1024;
- this._shadowBias = 0.00005;
- this._shadowDarkness = 1;
- this._shadowMinDepth = 1;
- this._shadowMaxDepth = 1000;
- this._shadowDepthScale = 50; // maybe need to change it if the distance between shadowMaxDepth and shadowMinDepth is small.
- this._frustumEdgeFalloff = 0; // used by directional and spot light.
- this._viewProjMatrix = mat4.create();
- this._spotAngleScale = 1; // used for spot light.
- this._shadowFustumSize = 80; // used for directional light.
-};
-
-var prototypeAccessors$4 = { color: { configurable: true },intensity: { configurable: true },type: { configurable: true },spotAngle: { configurable: true },spotExp: { configurable: true },range: { configurable: true },shadowType: { configurable: true },shadowMap: { configurable: true },viewProjMatrix: { configurable: true },shadowResolution: { configurable: true },shadowBias: { configurable: true },shadowDarkness: { configurable: true },shadowMinDepth: { configurable: true },shadowMaxDepth: { configurable: true },shadowDepthScale: { configurable: true },frustumEdgeFalloff: { configurable: true } };
-
-Light.prototype.setNode = function setNode (node) {
- this._node = node;
-};
-
-Light.prototype.setColor = function setColor (r, g, b) {
- color3.set(this._color, r, g, b);
- this._colorUniform[0] = r * this._intensity;
- this._colorUniform[1] = g * this._intensity;
- this._colorUniform[2] = b * this._intensity;
-};
-prototypeAccessors$4.color.get = function () {
- return this._color;
-};
-
-Light.prototype.setIntensity = function setIntensity (val) {
- this._intensity = val;
- this._colorUniform[0] = val * this._color.r;
- this._colorUniform[1] = val * this._color.g;
- this._colorUniform[2] = val * this._color.b;
-};
-prototypeAccessors$4.intensity.get = function () {
- return this._intensity;
-};
-
-Light.prototype.setType = function setType (tpe) {
- this._type = tpe;
-};
-prototypeAccessors$4.type.get = function () {
- return this._type;
-};
-
-Light.prototype.setSpotAngle = function setSpotAngle (val) {
- this._spotAngle = val;
- this._spotUniform[0] = Math.cos(this._spotAngle * 0.5);
-};
-prototypeAccessors$4.spotAngle.get = function () {
- return this._spotAngle;
-};
-
-Light.prototype.setSpotExp = function setSpotExp (val) {
- this._spotExp = val;
- this._spotUniform[1] = val;
-};
-prototypeAccessors$4.spotExp.get = function () {
- return this._spotExp;
-};
-
-Light.prototype.setRange = function setRange (tpe) {
- this._range = tpe;
-};
-prototypeAccessors$4.range.get = function () {
- return this._range;
-};
-
-Light.prototype.setShadowType = function setShadowType (type) {
- if (this._shadowType === enums.SHADOW_NONE && type !== enums.SHADOW_NONE) {
- this._shadowMapDirty = true;
- }
- this._shadowType = type;
-};
-prototypeAccessors$4.shadowType.get = function () {
- return this._shadowType;
-};
-
-prototypeAccessors$4.shadowMap.get = function () {
- return this._shadowMap;
-};
-
-prototypeAccessors$4.viewProjMatrix.get = function () {
- return this._viewProjMatrix;
-};
-
-Light.prototype.setShadowResolution = function setShadowResolution (val) {
- if (this._shadowResolution !== val) {
- this._shadowMapDirty = true;
- }
- this._shadowResolution = val;
-};
-prototypeAccessors$4.shadowResolution.get = function () {
- return this._shadowResolution;
-};
-
-Light.prototype.setShadowBias = function setShadowBias (val) {
- this._shadowBias = val;
-};
-prototypeAccessors$4.shadowBias.get = function () {
- return this._shadowBias;
-};
-
-Light.prototype.setShadowDarkness = function setShadowDarkness (val) {
- this._shadowDarkness = val;
-};
-prototypeAccessors$4.shadowDarkness.get = function () {
- return this._shadowDarkness;
-};
-
-Light.prototype.setShadowMinDepth = function setShadowMinDepth (val) {
- this._shadowMinDepth = val;
-};
-prototypeAccessors$4.shadowMinDepth.get = function () {
- if (this._type === enums.LIGHT_DIRECTIONAL) {
- return 1.0;
- }
- return this._shadowMinDepth;
-};
-
-Light.prototype.setShadowMaxDepth = function setShadowMaxDepth (val) {
- this._shadowMaxDepth = val;
-};
-prototypeAccessors$4.shadowMaxDepth.get = function () {
- if (this._type === enums.LIGHT_DIRECTIONAL) {
- return 1.0;
- }
- return this._shadowMaxDepth;
-};
-
-Light.prototype.setShadowDepthScale = function setShadowDepthScale (val) {
- this._shadowDepthScale = val;
-};
-prototypeAccessors$4.shadowDepthScale.get = function () {
- return this._shadowDepthScale;
-};
-
-Light.prototype.setFrustumEdgeFalloff = function setFrustumEdgeFalloff (val) {
- this._frustumEdgeFalloff = val;
-};
-prototypeAccessors$4.frustumEdgeFalloff.get = function () {
- return this._frustumEdgeFalloff;
-};
-
-Light.prototype.extractView = function extractView (out, stages) {
- // TODO: view should not handle light.
- out._shadowLight = this;
-
- // rect
- out._rect.x = 0;
- out._rect.y = 0;
- out._rect.w = this._shadowResolution;
- out._rect.h = this._shadowResolution;
-
- // clear opts
- color4.set(out._color, 1, 1, 1, 1);
- out._depth = 1;
- out._stencil = 0;
- out._clearFlags = enums.CLEAR_COLOR | enums.CLEAR_DEPTH;
-
- // stages & framebuffer
- out._stages = stages;
- out._framebuffer = this._shadowFrameBuffer;
-
- // view projection matrix
- switch(this._type) {
- case enums.LIGHT_SPOT:
- _computeSpotLightViewProjMatrix(this, out._matView, out._matProj);
- break;
-
- case enums.LIGHT_DIRECTIONAL:
- _computeDirectionalLightViewProjMatrix(this, out._matView, out._matProj);
- break;
-
- case enums.LIGHT_POINT:
- _computePointLightViewProjMatrix(this, out._matView, out._matProj);
- break;
-
- default:
- console.warn('shadow of this light type is not supported');
- }
-
- // view-projection
- mat4.mul(out._matViewProj, out._matProj, out._matView);
- this._viewProjMatrix = out._matViewProj;
- mat4.invert(out._matInvViewProj, out._matViewProj);
-};
-
-Light.prototype._updateLightPositionAndDirection = function _updateLightPositionAndDirection () {
- this._node.getWorldMatrix(_m4_tmp$1);
- mat3.fromMat4(_m3_tmp, _m4_tmp$1);
- vec3.transformMat3(_transformedLightDirection, _forward, _m3_tmp);
- vec3.array(this._directionUniform, _transformedLightDirection);
- var pos = this._positionUniform;
- pos[0] = _m4_tmp$1.m12;
- pos[1] = _m4_tmp$1.m13;
- pos[2] = _m4_tmp$1.m14;
-};
-
-Light.prototype._generateShadowMap = function _generateShadowMap (device) {
- this._shadowMap = new gfx.Texture2D(device, {
- width: this._shadowResolution,
- height: this._shadowResolution,
- format: gfx.TEXTURE_FMT_RGBA8,
- wrapS: gfx.WRAP_CLAMP,
- wrapT: gfx.WRAP_CLAMP,
- });
- this._shadowDepthBuffer = new gfx.RenderBuffer(device,
- gfx.RB_FMT_D16,
- this._shadowResolution,
- this._shadowResolution
- );
- this._shadowFrameBuffer = new gfx.FrameBuffer(device, this._shadowResolution, this._shadowResolution, {
- colors: [this._shadowMap],
- depth: this._shadowDepthBuffer,
- });
-};
-
-Light.prototype._destroyShadowMap = function _destroyShadowMap () {
- if (this._shadowMap) {
- this._shadowMap.destroy();
- this._shadowDepthBuffer.destroy();
- this._shadowFrameBuffer.destroy();
- this._shadowMap = null;
- this._shadowDepthBuffer = null;
- this._shadowFrameBuffer = null;
- }
-};
-
-Light.prototype.update = function update (device) {
- this._updateLightPositionAndDirection();
-
- if (this._shadowType === enums.SHADOW_NONE) {
- this._destroyShadowMap();
- } else if (this._shadowMapDirty) {
- this._destroyShadowMap();
- this._generateShadowMap(device);
- this._shadowMapDirty = false;
- }
-
-};
-
-Object.defineProperties( Light.prototype, prototypeAccessors$4 );
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var _matView = mat4.create();
-var _matProj = mat4.create();
-var _matViewProj = mat4.create();
-var _matInvViewProj = mat4.create();
-var _tmp_v3 = vec3.create();
-
-var Camera = function Camera() {
- this._poolID = -1;
- this._node = null;
-
- //
- this._projection = enums.PROJ_PERSPECTIVE;
-
- // clear options
- this._color = color4.new(0.2, 0.3, 0.47, 1);
- this._depth = 1;
- this._stencil = 0;
- this._sortDepth = 0;
- this._clearFlags = enums.CLEAR_COLOR | enums.CLEAR_DEPTH;
-
- // culling mask
- this._cullingMask = 1;
-
- // stages & framebuffer
- this._stages = [];
- this._framebuffer = null;
-
- // projection properties
- this._near = 0.01;
- this._far = 1000.0;
- this._fov = Math.PI/4.0; // vertical fov
- // this._aspect = 16.0/9.0; // DISABLE: use _rect.w/_rect.h
- this._rect = {
- x: 0, y: 0, w: 1, h: 1
- };
-
- // ortho properties
- this._orthoHeight = 10;
-};
-
-var prototypeAccessors$5 = { cullingMask: { configurable: true } };
-
-// culling mask
-prototypeAccessors$5.cullingMask.get = function () {
- return this._cullingMask;
-};
-
-prototypeAccessors$5.cullingMask.set = function (mask) {
- this._cullingMask = mask;
-};
-
-// node
-Camera.prototype.getNode = function getNode () {
- return this._node;
-};
-Camera.prototype.setNode = function setNode (node) {
- this._node = node;
-};
-
-// type
-Camera.prototype.getType = function getType () {
- return this._projection;
-};
-Camera.prototype.setType = function setType (type) {
- this._projection = type;
-};
-
-// orthoHeight
-Camera.prototype.getOrthoHeight = function getOrthoHeight () {
- return this._orthoHeight;
-};
-Camera.prototype.setOrthoHeight = function setOrthoHeight (val) {
- this._orthoHeight = val;
-};
-
-// fov
-Camera.prototype.getFov = function getFov () {
- return this._fov;
-};
-Camera.prototype.setFov = function setFov (fov) {
- this._fov = fov;
-};
-
-// near
-Camera.prototype.getNear = function getNear () {
- return this._near;
-};
-Camera.prototype.setNear = function setNear (near) {
- this._near = near;
-};
-
-// far
-Camera.prototype.getFar = function getFar () {
- return this._far;
-};
-Camera.prototype.setFar = function setFar (far) {
- this._far = far;
-};
-
-// color
-Camera.prototype.getColor = function getColor (out) {
- return color4.copy(out, this._color);
-};
-Camera.prototype.setColor = function setColor (r, g, b, a) {
- color4.set(this._color, r, g, b, a);
-};
-
-// depth
-Camera.prototype.getDepth = function getDepth () {
- return this._depth;
-};
-Camera.prototype.setDepth = function setDepth (depth) {
- this._depth = depth;
-};
-
-// stencil
-Camera.prototype.getStencil = function getStencil () {
- return this._stencil;
-};
-Camera.prototype.setStencil = function setStencil (stencil) {
- this._stencil = stencil;
-};
-
-// clearFlags
-Camera.prototype.getClearFlags = function getClearFlags () {
- return this._clearFlags;
-};
-Camera.prototype.setClearFlags = function setClearFlags (flags) {
- this._clearFlags = flags;
-};
-
-// rect
-Camera.prototype.getRect = function getRect (out) {
- out.x = this._rect.x;
- out.y = this._rect.y;
- out.w = this._rect.w;
- out.h = this._rect.h;
-
- return out;
-};
-/**
- * @param {Number} x - [0,1]
- * @param {Number} y - [0,1]
- * @param {Number} w - [0,1]
- * @param {Number} h - [0,1]
- */
-Camera.prototype.setRect = function setRect (x, y, w, h) {
- this._rect.x = x;
- this._rect.y = y;
- this._rect.w = w;
- this._rect.h = h;
-};
-
-// stages
-Camera.prototype.getStages = function getStages () {
- return this._stages;
-};
-Camera.prototype.setStages = function setStages (stages) {
- this._stages = stages;
-};
-
-// framebuffer
-Camera.prototype.getFramebuffer = function getFramebuffer () {
- return this._framebuffer;
-};
-Camera.prototype.setFramebuffer = function setFramebuffer (framebuffer) {
- this._framebuffer = framebuffer;
-};
-
-Camera.prototype.extractView = function extractView (out, width, height) {
- // rect
- out._rect.x = this._rect.x * width;
- out._rect.y = this._rect.y * height;
- out._rect.w = this._rect.w * width;
- out._rect.h = this._rect.h * height;
-
- // clear opts
- out._color = this._color;
- out._depth = this._depth;
- out._stencil = this._stencil;
- out._clearFlags = this._clearFlags;
-
- // culling mask
- out._cullingMask = this._cullingMask;
-
- // stages & framebuffer
- out._stages = this._stages;
- out._framebuffer = this._framebuffer;
-
- // view matrix
- this._node.getWorldRT(out._matView);
- mat4.invert(out._matView, out._matView);
-
- // projection matrix
- // TODO: if this._projDirty
- var aspect = width / height;
- if (this._projection === enums.PROJ_PERSPECTIVE) {
- mat4.perspective(out._matProj,
- this._fov,
- aspect,
- this._near,
- this._far
- );
- } else {
- var x = this._orthoHeight * aspect;
- var y = this._orthoHeight;
- mat4.ortho(out._matProj,
- -x, x, -y, y, this._near, this._far
- );
- }
-
- // view-projection
- mat4.mul(out._matViewProj, out._matProj, out._matView);
- mat4.invert(out._matInvViewProj, out._matViewProj);
-};
-
-Camera.prototype.screenToWorld = function screenToWorld (out, screenPos, width, height) {
- var aspect = width / height;
- var cx = this._rect.x * width;
- var cy = this._rect.y * height;
- var cw = this._rect.w * width;
- var ch = this._rect.h * height;
-
- // view matrix
- this._node.getWorldRT(_matView);
- mat4.invert(_matView, _matView);
-
- // projection matrix
- if (this._projection === enums.PROJ_PERSPECTIVE) {
- mat4.perspective(_matProj,
- this._fov,
- aspect,
- this._near,
- this._far
- );
- } else {
- var x = this._orthoHeight * aspect;
- var y = this._orthoHeight;
- mat4.ortho(_matProj,
- -x, x, -y, y, this._near, this._far
- );
- }
-
- // view-projection
- mat4.mul(_matViewProj, _matProj, _matView);
-
- // inv view-projection
- mat4.invert(_matInvViewProj, _matViewProj);
-
- //
- if (this._projection === enums.PROJ_PERSPECTIVE) {
- // calculate screen pos in far clip plane
- vec3.set(out,
- (screenPos.x - cx) * 2.0 / cw - 1.0,
- (screenPos.y - cy) * 2.0 / ch - 1.0, // DISABLE: (ch - (screenPos.y - cy)) * 2.0 / ch - 1.0,
- 1.0
- );
-
- // transform to world
- vec3.transformMat4(out, out, _matInvViewProj);
-
- //
- this._node.getWorldPos(_tmp_v3);
- vec3.lerp(out, _tmp_v3, out, screenPos.z / this._far);
- } else {
- var range = this._farClip - this._nearClip;
- vec3.set(out,
- (screenPos.x - cx) * 2.0 / cw - 1.0,
- (screenPos.y - cy) * 2.0 / ch - 1.0, // DISABLE: (ch - (screenPos.y - cy)) * 2.0 / ch - 1.0,
- (this._far - screenPos.z) / range * 2.0 - 1.0
- );
-
- // transform to world
- vec3.transformMat4(out, out, _matInvViewProj);
- }
-
- return out;
-};
-
-Camera.prototype.worldToScreen = function worldToScreen (out, worldPos, width, height) {
- var aspect = width / height;
- var cx = this._rect.x * width;
- var cy = this._rect.y * height;
- var cw = this._rect.w * width;
- var ch = this._rect.h * height;
-
- // view matrix
- this._node.getWorldRT(_matView);
- mat4.invert(_matView, _matView);
-
- // projection matrix
- if (this._projection === enums.PROJ_PERSPECTIVE) {
- mat4.perspective(_matProj,
- this._fov,
- aspect,
- this._near,
- this._far
- );
- } else {
- var x = this._orthoHeight * aspect;
- var y = this._orthoHeight;
- mat4.ortho(_matProj,
- -x, x, -y, y, this._near, this._far
- );
- }
-
- // view-projection
- mat4.mul(_matViewProj, _matProj, _matView);
-
- // calculate w
- var w =
- worldPos.x * _matViewProj.m03 +
- worldPos.y * _matViewProj.m07 +
- worldPos.z * _matViewProj.m11 +
- _matViewProj.m15;
-
- vec3.transformMat4(out, worldPos, _matViewProj);
- out.x = cx + (out.x / w + 1) * 0.5 * cw;
- out.y = cy + (out.y / w + 1) * 0.5 * ch;
-
- return out;
-};
-
-Object.defineProperties( Camera.prototype, prototypeAccessors$5 );
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var Model = function Model() {
- this._poolID = -1;
- this._node = null;
- this._inputAssemblers = [];
- this._effects = [];
- this._defines = [];
- this._dynamicIA = false;
- this._cullingMask = -1;
-
- // TODO: we calculate aabb based on vertices
- // this._aabb
-};
-
-var prototypeAccessors$6 = { inputAssemblerCount: { configurable: true },dynamicIA: { configurable: true },drawItemCount: { configurable: true },cullingMask: { configurable: true } };
-
-prototypeAccessors$6.inputAssemblerCount.get = function () {
- return this._inputAssemblers.length;
-};
-
-prototypeAccessors$6.dynamicIA.get = function () {
- return this._dynamicIA;
-};
-
-prototypeAccessors$6.drawItemCount.get = function () {
- return this._dynamicIA ? 1 : this._inputAssemblers.length;
-};
-
-prototypeAccessors$6.cullingMask.get = function () {
- return this._cullingMask;
-};
-
-prototypeAccessors$6.cullingMask.set = function (mask) {
- this._cullingMask = mask;
-};
-
-Model.prototype.setNode = function setNode (node) {
- this._node = node;
-};
-
-Model.prototype.setDynamicIA = function setDynamicIA (enabled) {
- this._dynamicIA = enabled;
-};
-
-Model.prototype.addInputAssembler = function addInputAssembler (ia) {
- if (this._inputAssemblers.indexOf(ia) !== -1) {
- return;
- }
- this._inputAssemblers.push(ia);
-};
-
-Model.prototype.clearInputAssemblers = function clearInputAssemblers () {
- this._inputAssemblers.length = 0;
-};
-
-Model.prototype.addEffect = function addEffect (effect) {
- if (this._effects.indexOf(effect) !== -1) {
- return;
- }
- this._effects.push(effect);
-
- //
- var defs = Object.create(null);
- effect.extractDefines(defs);
- this._defines.push(defs);
-};
-
-Model.prototype.clearEffects = function clearEffects () {
- this._effects.length = 0;
- this._defines.length = 0;
-};
-
-Model.prototype.extractDrawItem = function extractDrawItem (out, index) {
- if (this._dynamicIA) {
- out.model = this;
- out.node = this._node;
- out.ia = null;
- out.effect = this._effects[0];
- out.defines = out.effect.extractDefines(this._defines[0]);
-
- return;
- }
-
- if (index >= this._inputAssemblers.length ) {
- out.model = null;
- out.node = null;
- out.ia = null;
- out.effect = null;
- out.defines = null;
-
- return;
- }
-
- out.model = this;
- out.node = this._node;
- out.ia = this._inputAssemblers[index];
-
- var effect, defines;
- if (index < this._effects.length) {
- effect = this._effects[index];
- defines = this._defines[index];
- } else {
- effect = this._effects[this._effects.length-1];
- defines = this._defines[this._effects.length-1];
- }
- out.effect = effect;
- out.defines = effect.extractDefines(defines);
-};
-
-Object.defineProperties( Model.prototype, prototypeAccessors$6 );
-
-// reference: https://github.com/mziccard/node-timsort
-
-/**
- * Default minimum size of a run.
- */
-var DEFAULT_MIN_MERGE = 32;
-
-/**
- * Minimum ordered subsequece required to do galloping.
- */
-var DEFAULT_MIN_GALLOPING = 7;
-
-/**
- * Default tmp storage length. Can increase depending on the size of the
- * smallest run to merge.
- */
-var DEFAULT_TMP_STORAGE_LENGTH = 256;
-
-/**
- * Pre-computed powers of 10 for efficient lexicographic comparison of
- * small integers.
- */
-var POWERS_OF_TEN = [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9];
-
-/**
- * Estimate the logarithm base 10 of a small integer.
- *
- * @param {number} x - The integer to estimate the logarithm of.
- * @return {number} - The estimated logarithm of the integer.
- */
-function log10$1(x) {
- if (x < 1e5) {
- if (x < 1e2) {
- return x < 1e1 ? 0 : 1;
- }
-
- if (x < 1e4) {
- return x < 1e3 ? 2 : 3;
- }
-
- return 4;
- }
-
- if (x < 1e7) {
- return x < 1e6 ? 5 : 6;
- }
-
- if (x < 1e9) {
- return x < 1e8 ? 7 : 8;
- }
-
- return 9;
-}
-
-/**
- * Default alphabetical comparison of items.
- *
- * @param {string|object|number} a - First element to compare.
- * @param {string|object|number} b - Second element to compare.
- * @return {number} - A positive number if a.toString() > b.toString(), a
- * negative number if .toString() < b.toString(), 0 otherwise.
- */
-function alphabeticalCompare(a, b) {
- if (a === b) {
- return 0;
- }
-
- if (~~a === a && ~~b === b) {
- if (a === 0 || b === 0) {
- return a < b ? -1 : 1;
- }
-
- if (a < 0 || b < 0) {
- if (b >= 0) {
- return -1;
- }
-
- if (a >= 0) {
- return 1;
- }
-
- a = -a;
- b = -b;
- }
-
- var al = log10$1(a);
- var bl = log10$1(b);
-
- var t = 0;
-
- if (al < bl) {
- a *= POWERS_OF_TEN[bl - al - 1];
- b /= 10;
- t = -1;
- } else if (al > bl) {
- b *= POWERS_OF_TEN[al - bl - 1];
- a /= 10;
- t = 1;
- }
-
- if (a === b) {
- return t;
- }
-
- return a < b ? -1 : 1;
- }
-
- var aStr = String(a);
- var bStr = String(b);
-
- if (aStr === bStr) {
- return 0;
- }
-
- return aStr < bStr ? -1 : 1;
-}
-
-/**
- * Compute minimum run length for TimSort
- *
- * @param {number} n - The size of the array to sort.
- */
-function minRunLength(n) {
- var r = 0;
-
- while (n >= DEFAULT_MIN_MERGE) {
- r |= (n & 1);
- n >>= 1;
- }
-
- return n + r;
-}
-
-/**
- * Counts the length of a monotonically ascending or strictly monotonically
- * descending sequence (run) starting at array[lo] in the range [lo, hi). If
- * the run is descending it is made ascending.
- *
- * @param {array} array - The array to reverse.
- * @param {number} lo - First element in the range (inclusive).
- * @param {number} hi - Last element in the range.
- * @param {function} compare - Item comparison function.
- * @return {number} - The length of the run.
- */
-function makeAscendingRun(array, lo, hi, compare) {
- var runHi = lo + 1;
-
- if (runHi === hi) {
- return 1;
- }
-
- // Descending
- if (compare(array[runHi++], array[lo]) < 0) {
- while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) {
- runHi++;
- }
-
- reverseRun(array, lo, runHi);
- // Ascending
- } else {
- while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) {
- runHi++;
- }
- }
-
- return runHi - lo;
-}
-
-/**
- * Reverse an array in the range [lo, hi).
- *
- * @param {array} array - The array to reverse.
- * @param {number} lo - First element in the range (inclusive).
- * @param {number} hi - Last element in the range.
- */
-function reverseRun(array, lo, hi) {
- hi--;
-
- while (lo < hi) {
- var t = array[lo];
- array[lo++] = array[hi];
- array[hi--] = t;
- }
-}
-
-/**
- * Perform the binary sort of the array in the range [lo, hi) where start is
- * the first element possibly out of order.
- *
- * @param {array} array - The array to sort.
- * @param {number} lo - First element in the range (inclusive).
- * @param {number} hi - Last element in the range.
- * @param {number} start - First element possibly out of order.
- * @param {function} compare - Item comparison function.
- */
-function binaryInsertionSort(array, lo, hi, start, compare) {
- if (start === lo) {
- start++;
- }
-
- for (; start < hi; start++) {
- var pivot = array[start];
-
- // Ranges of the array where pivot belongs
- var left = lo;
- var right = start;
-
- /*
- * pivot >= array[i] for i in [lo, left)
- * pivot < array[i] for i in in [right, start)
- */
- while (left < right) {
- var mid = (left + right) >>> 1;
-
- if (compare(pivot, array[mid]) < 0) {
- right = mid;
- } else {
- left = mid + 1;
- }
- }
-
- /*
- * Move elements right to make room for the pivot. If there are elements
- * equal to pivot, left points to the first slot after them: this is also
- * a reason for which TimSort is stable
- */
- var n = start - left;
- // Switch is just an optimization for small arrays
- switch (n) {
- case 3:
- array[left + 3] = array[left + 2];
- /* falls through */
- case 2:
- array[left + 2] = array[left + 1];
- /* falls through */
- case 1:
- array[left + 1] = array[left];
- break;
- default:
- while (n > 0) {
- array[left + n] = array[left + n - 1];
- n--;
- }
- }
-
- array[left] = pivot;
- }
-}
-
-/**
- * Find the position at which to insert a value in a sorted range. If the range
- * contains elements equal to the value the leftmost element index is returned
- * (for stability).
- *
- * @param {number} value - Value to insert.
- * @param {array} array - The array in which to insert value.
- * @param {number} start - First element in the range.
- * @param {number} length - Length of the range.
- * @param {number} hint - The index at which to begin the search.
- * @param {function} compare - Item comparison function.
- * @return {number} - The index where to insert value.
- */
-function gallopLeft(value, array, start, length, hint, compare) {
- var lastOffset = 0;
- var maxOffset = 0;
- var offset = 1;
-
- if (compare(value, array[start + hint]) > 0) {
- maxOffset = length - hint;
-
- while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) {
- lastOffset = offset;
- offset = (offset << 1) + 1;
-
- if (offset <= 0) {
- offset = maxOffset;
- }
- }
-
- if (offset > maxOffset) {
- offset = maxOffset;
- }
-
- // Make offsets relative to start
- lastOffset += hint;
- offset += hint;
-
- // value <= array[start + hint]
- } else {
- maxOffset = hint + 1;
- while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) {
- lastOffset = offset;
- offset = (offset << 1) + 1;
-
- if (offset <= 0) {
- offset = maxOffset;
- }
- }
- if (offset > maxOffset) {
- offset = maxOffset;
- }
-
- // Make offsets relative to start
- var tmp = lastOffset;
- lastOffset = hint - offset;
- offset = hint - tmp;
- }
-
- /*
- * Now array[start+lastOffset] < value <= array[start+offset], so value
- * belongs somewhere in the range (start + lastOffset, start + offset]. Do a
- * binary search, with invariant array[start + lastOffset - 1] < value <=
- * array[start + offset].
- */
- lastOffset++;
- while (lastOffset < offset) {
- var m = lastOffset + ((offset - lastOffset) >>> 1);
-
- if (compare(value, array[start + m]) > 0) {
- lastOffset = m + 1;
-
- } else {
- offset = m;
- }
- }
- return offset;
-}
-
-/**
- * Find the position at which to insert a value in a sorted range. If the range
- * contains elements equal to the value the rightmost element index is returned
- * (for stability).
- *
- * @param {number} value - Value to insert.
- * @param {array} array - The array in which to insert value.
- * @param {number} start - First element in the range.
- * @param {number} length - Length of the range.
- * @param {number} hint - The index at which to begin the search.
- * @param {function} compare - Item comparison function.
- * @return {number} - The index where to insert value.
- */
-function gallopRight(value, array, start, length, hint, compare) {
- var lastOffset = 0;
- var maxOffset = 0;
- var offset = 1;
-
- if (compare(value, array[start + hint]) < 0) {
- maxOffset = hint + 1;
-
- while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) {
- lastOffset = offset;
- offset = (offset << 1) + 1;
-
- if (offset <= 0) {
- offset = maxOffset;
- }
- }
-
- if (offset > maxOffset) {
- offset = maxOffset;
- }
-
- // Make offsets relative to start
- var tmp = lastOffset;
- lastOffset = hint - offset;
- offset = hint - tmp;
-
- // value >= array[start + hint]
- } else {
- maxOffset = length - hint;
-
- while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) {
- lastOffset = offset;
- offset = (offset << 1) + 1;
-
- if (offset <= 0) {
- offset = maxOffset;
- }
- }
-
- if (offset > maxOffset) {
- offset = maxOffset;
- }
-
- // Make offsets relative to start
- lastOffset += hint;
- offset += hint;
- }
-
- /*
- * Now array[start+lastOffset] < value <= array[start+offset], so value
- * belongs somewhere in the range (start + lastOffset, start + offset]. Do a
- * binary search, with invariant array[start + lastOffset - 1] < value <=
- * array[start + offset].
- */
- lastOffset++;
-
- while (lastOffset < offset) {
- var m = lastOffset + ((offset - lastOffset) >>> 1);
-
- if (compare(value, array[start + m]) < 0) {
- offset = m;
-
- } else {
- lastOffset = m + 1;
- }
- }
-
- return offset;
-}
-
-var TimSort = function TimSort(array, compare) {
- this.array = array;
- this.compare = compare;
- this.minGallop = DEFAULT_MIN_GALLOPING;
- this.length = array.length;
-
- this.tmpStorageLength = DEFAULT_TMP_STORAGE_LENGTH;
- if (this.length < 2 * DEFAULT_TMP_STORAGE_LENGTH) {
- this.tmpStorageLength = this.length >>> 1;
- }
-
- this.tmp = new Array(this.tmpStorageLength);
-
- this.stackLength =
- (this.length < 120 ? 5 :
- this.length < 1542 ? 10 :
- this.length < 119151 ? 19 : 40);
-
- this.runStart = new Array(this.stackLength);
- this.runLength = new Array(this.stackLength);
- this.stackSize = 0;
-};
-
-/**
- * Push a new run on TimSort's stack.
- *
- * @param {number} runStart - Start index of the run in the original array.
- * @param {number} runLength - Length of the run;
- */
-TimSort.prototype.pushRun = function pushRun (runStart, runLength) {
- this.runStart[this.stackSize] = runStart;
- this.runLength[this.stackSize] = runLength;
- this.stackSize += 1;
-};
-
-/**
- * Merge runs on TimSort's stack so that the following holds for all i:
- * 1) runLength[i - 3] > runLength[i - 2] + runLength[i - 1]
- * 2) runLength[i - 2] > runLength[i - 1]
- */
-TimSort.prototype.mergeRuns = function mergeRuns () {
- var this$1 = this;
-
- while (this.stackSize > 1) {
- var n = this$1.stackSize - 2;
-
- if ((n >= 1 &&
- this$1.runLength[n - 1] <= this$1.runLength[n] + this$1.runLength[n + 1]) ||
- (n >= 2 &&
- this$1.runLength[n - 2] <= this$1.runLength[n] + this$1.runLength[n - 1])) {
-
- if (this$1.runLength[n - 1] < this$1.runLength[n + 1]) {
- n--;
- }
-
- } else if (this$1.runLength[n] > this$1.runLength[n + 1]) {
- break;
- }
- this$1.mergeAt(n);
- }
-};
-
-/**
- * Merge all runs on TimSort's stack until only one remains.
- */
-TimSort.prototype.forceMergeRuns = function forceMergeRuns () {
- var this$1 = this;
-
- while (this.stackSize > 1) {
- var n = this$1.stackSize - 2;
-
- if (n > 0 && this$1.runLength[n - 1] < this$1.runLength[n + 1]) {
- n--;
- }
-
- this$1.mergeAt(n);
- }
-};
-
-/**
- * Merge the runs on the stack at positions i and i+1. Must be always be called
- * with i=stackSize-2 or i=stackSize-3 (that is, we merge on top of the stack).
- *
- * @param {number} i - Index of the run to merge in TimSort's stack.
- */
-TimSort.prototype.mergeAt = function mergeAt (i) {
- var compare = this.compare;
- var array = this.array;
-
- var start1 = this.runStart[i];
- var length1 = this.runLength[i];
- var start2 = this.runStart[i + 1];
- var length2 = this.runLength[i + 1];
-
- this.runLength[i] = length1 + length2;
-
- if (i === this.stackSize - 3) {
- this.runStart[i + 1] = this.runStart[i + 2];
- this.runLength[i + 1] = this.runLength[i + 2];
- }
-
- this.stackSize--;
-
- /*
- * Find where the first element in the second run goes in run1. Previous
- * elements in run1 are already in place
- */
- var k = gallopRight(array[start2], array, start1, length1, 0, compare);
- start1 += k;
- length1 -= k;
-
- if (length1 === 0) {
- return;
- }
-
- /*
- * Find where the last element in the first run goes in run2. Next elements
- * in run2 are already in place
- */
- length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare);
-
- if (length2 === 0) {
- return;
- }
-
- /*
- * Merge remaining runs. A tmp array with length = min(length1, length2) is
- * used
- */
- if (length1 <= length2) {
- this.mergeLow(start1, length1, start2, length2);
-
- } else {
- this.mergeHigh(start1, length1, start2, length2);
- }
-};
-
-/**
- * Merge two adjacent runs in a stable way. The runs must be such that the
- * first element of run1 is bigger than the first element in run2 and the
- * last element of run1 is greater than all the elements in run2.
- * The method should be called when run1.length <= run2.length as it uses
- * TimSort temporary array to store run1. Use mergeHigh if run1.length >
- * run2.length.
- *
- * @param {number} start1 - First element in run1.
- * @param {number} length1 - Length of run1.
- * @param {number} start2 - First element in run2.
- * @param {number} length2 - Length of run2.
- */
-TimSort.prototype.mergeLow = function mergeLow (start1, length1, start2, length2) {
-
- var compare = this.compare;
- var array = this.array;
- var tmp = this.tmp;
- var i = 0;
-
- for (i = 0; i < length1; i++) {
- tmp[i] = array[start1 + i];
- }
-
- var cursor1 = 0;
- var cursor2 = start2;
- var dest = start1;
-
- array[dest++] = array[cursor2++];
-
- if (--length2 === 0) {
- for (i = 0; i < length1; i++) {
- array[dest + i] = tmp[cursor1 + i];
- }
- return;
- }
-
- if (length1 === 1) {
- for (i = 0; i < length2; i++) {
- array[dest + i] = array[cursor2 + i];
- }
- array[dest + length2] = tmp[cursor1];
- return;
- }
-
- var minGallop = this.minGallop;
-
- while (true) {
- var count1 = 0;
- var count2 = 0;
- var exit = false;
-
- do {
- if (compare(array[cursor2], tmp[cursor1]) < 0) {
- array[dest++] = array[cursor2++];
- count2++;
- count1 = 0;
-
- if (--length2 === 0) {
- exit = true;
- break;
- }
-
- } else {
- array[dest++] = tmp[cursor1++];
- count1++;
- count2 = 0;
- if (--length1 === 1) {
- exit = true;
- break;
- }
- }
- } while ((count1 | count2) < minGallop);
-
- if (exit) {
- break;
- }
-
- do {
- count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare);
-
- if (count1 !== 0) {
- for (i = 0; i < count1; i++) {
- array[dest + i] = tmp[cursor1 + i];
- }
-
- dest += count1;
- cursor1 += count1;
- length1 -= count1;
- if (length1 <= 1) {
- exit = true;
- break;
- }
- }
-
- array[dest++] = array[cursor2++];
-
- if (--length2 === 0) {
- exit = true;
- break;
- }
-
- count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare);
-
- if (count2 !== 0) {
- for (i = 0; i < count2; i++) {
- array[dest + i] = array[cursor2 + i];
- }
-
- dest += count2;
- cursor2 += count2;
- length2 -= count2;
-
- if (length2 === 0) {
- exit = true;
- break;
- }
- }
- array[dest++] = tmp[cursor1++];
-
- if (--length1 === 1) {
- exit = true;
- break;
- }
-
- minGallop--;
-
- } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
-
- if (exit) {
- break;
- }
-
- if (minGallop < 0) {
- minGallop = 0;
- }
-
- minGallop += 2;
- }
-
- this.minGallop = minGallop;
-
- if (minGallop < 1) {
- this.minGallop = 1;
- }
-
- if (length1 === 1) {
- for (i = 0; i < length2; i++) {
- array[dest + i] = array[cursor2 + i];
- }
- array[dest + length2] = tmp[cursor1];
-
- } else if (length1 === 0) {
- throw new Error('mergeLow preconditions were not respected');
-
- } else {
- for (i = 0; i < length1; i++) {
- array[dest + i] = tmp[cursor1 + i];
- }
- }
-};
-
-/**
- * Merge two adjacent runs in a stable way. The runs must be such that the
- * first element of run1 is bigger than the first element in run2 and the
- * last element of run1 is greater than all the elements in run2.
- * The method should be called when run1.length > run2.length as it uses
- * TimSort temporary array to store run2. Use mergeLow if run1.length <=
- * run2.length.
- *
- * @param {number} start1 - First element in run1.
- * @param {number} length1 - Length of run1.
- * @param {number} start2 - First element in run2.
- * @param {number} length2 - Length of run2.
- */
-TimSort.prototype.mergeHigh = function mergeHigh (start1, length1, start2, length2) {
- var compare = this.compare;
- var array = this.array;
- var tmp = this.tmp;
- var i = 0;
-
- for (i = 0; i < length2; i++) {
- tmp[i] = array[start2 + i];
- }
-
- var cursor1 = start1 + length1 - 1;
- var cursor2 = length2 - 1;
- var dest = start2 + length2 - 1;
- var customCursor = 0;
- var customDest = 0;
-
- array[dest--] = array[cursor1--];
-
- if (--length1 === 0) {
- customCursor = dest - (length2 - 1);
-
- for (i = 0; i < length2; i++) {
- array[customCursor + i] = tmp[i];
- }
-
- return;
- }
-
- if (length2 === 1) {
- dest -= length1;
- cursor1 -= length1;
- customDest = dest + 1;
- customCursor = cursor1 + 1;
-
- for (i = length1 - 1; i >= 0; i--) {
- array[customDest + i] = array[customCursor + i];
- }
-
- array[dest] = tmp[cursor2];
- return;
- }
-
- var minGallop = this.minGallop;
-
- while (true) {
- var count1 = 0;
- var count2 = 0;
- var exit = false;
-
- do {
- if (compare(tmp[cursor2], array[cursor1]) < 0) {
- array[dest--] = array[cursor1--];
- count1++;
- count2 = 0;
- if (--length1 === 0) {
- exit = true;
- break;
- }
-
- } else {
- array[dest--] = tmp[cursor2--];
- count2++;
- count1 = 0;
- if (--length2 === 1) {
- exit = true;
- break;
- }
- }
-
- } while ((count1 | count2) < minGallop);
-
- if (exit) {
- break;
- }
-
- do {
- count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare);
-
- if (count1 !== 0) {
- dest -= count1;
- cursor1 -= count1;
- length1 -= count1;
- customDest = dest + 1;
- customCursor = cursor1 + 1;
-
- for (i = count1 - 1; i >= 0; i--) {
- array[customDest + i] = array[customCursor + i];
- }
-
- if (length1 === 0) {
- exit = true;
- break;
- }
- }
-
- array[dest--] = tmp[cursor2--];
-
- if (--length2 === 1) {
- exit = true;
- break;
- }
-
- count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare);
-
- if (count2 !== 0) {
- dest -= count2;
- cursor2 -= count2;
- length2 -= count2;
- customDest = dest + 1;
- customCursor = cursor2 + 1;
-
- for (i = 0; i < count2; i++) {
- array[customDest + i] = tmp[customCursor + i];
- }
-
- if (length2 <= 1) {
- exit = true;
- break;
- }
- }
-
- array[dest--] = array[cursor1--];
-
- if (--length1 === 0) {
- exit = true;
- break;
- }
-
- minGallop--;
-
- } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
-
- if (exit) {
- break;
- }
-
- if (minGallop < 0) {
- minGallop = 0;
- }
-
- minGallop += 2;
- }
-
- this.minGallop = minGallop;
-
- if (minGallop < 1) {
- this.minGallop = 1;
- }
-
- if (length2 === 1) {
- dest -= length1;
- cursor1 -= length1;
- customDest = dest + 1;
- customCursor = cursor1 + 1;
-
- for (i = length1 - 1; i >= 0; i--) {
- array[customDest + i] = array[customCursor + i];
- }
-
- array[dest] = tmp[cursor2];
-
- } else if (length2 === 0) {
- throw new Error('mergeHigh preconditions were not respected');
-
- } else {
- customCursor = dest - (length2 - 1);
- for (i = 0; i < length2; i++) {
- array[customCursor + i] = tmp[i];
- }
- }
-};
-
-/**
- * Sort an array in the range [lo, hi) using TimSort.
- *
- * @param {array} array - The array to sort.
- * @param {number} lo - First element in the range (inclusive).
- * @param {number} hi - Last element in the range.
- * @param {function=} compare - Item comparison function. Default is alphabetical.
- */
-function sort (array, lo, hi, compare) {
- if (!Array.isArray(array)) {
- throw new TypeError('Can only sort arrays');
- }
-
- /*
- * Handle the case where a comparison function is not provided. We do
- * lexicographic sorting
- */
-
- if (lo === undefined) {
- lo = 0;
- }
-
- if (hi === undefined) {
- hi = array.length;
- }
-
- if (compare === undefined) {
- compare = alphabeticalCompare;
- }
-
- var remaining = hi - lo;
-
- // The array is already sorted
- if (remaining < 2) {
- return;
- }
-
- var runLength = 0;
- // On small arrays binary sort can be used directly
- if (remaining < DEFAULT_MIN_MERGE) {
- runLength = makeAscendingRun(array, lo, hi, compare);
- binaryInsertionSort(array, lo, hi, lo + runLength, compare);
- return;
- }
-
- var ts = new TimSort(array, compare);
-
- var minRun = minRunLength(remaining);
-
- do {
- runLength = makeAscendingRun(array, lo, hi, compare);
- if (runLength < minRun) {
- var force = remaining;
- if (force > minRun) {
- force = minRun;
- }
-
- binaryInsertionSort(array, lo, lo + force, lo + runLength, compare);
- runLength = force;
- }
- // Push new run and merge if necessary
- ts.pushRun(lo, runLength);
- ts.mergeRuns();
-
- // Go find next run
- remaining -= runLength;
- lo += runLength;
-
- } while (remaining !== 0);
-
- // Force merging of remaining runs
- ts.forceMergeRuns();
-}
-
-var FixedArray = function FixedArray(size) {
- this._count = 0;
- this._data = new Array(size);
-};
-
-var prototypeAccessors$7 = { length: { configurable: true },data: { configurable: true } };
-
-FixedArray.prototype._resize = function _resize (size) {
- var this$1 = this;
-
- if (size > this._data.length) {
- for (var i = this._data.length; i < size; ++i) {
- this$1._data[i] = undefined;
- }
- }
-};
-
-prototypeAccessors$7.length.get = function () {
- return this._count;
-};
-
-prototypeAccessors$7.data.get = function () {
- return this._data;
-};
-
-FixedArray.prototype.reset = function reset () {
- var this$1 = this;
-
- for (var i = 0; i < this._count; ++i) {
- this$1._data[i] = undefined;
- }
-
- this._count = 0;
-};
-
-FixedArray.prototype.push = function push (val) {
- if (this._count >= this._data.length) {
- this._resize(this._data.length * 2);
- }
-
- this._data[this._count] = val;
- ++this._count;
-};
-
-FixedArray.prototype.pop = function pop () {
- --this._count;
-
- if (this._count < 0) {
- this._count = 0;
- }
-
- var ret = this._data[this._count];
- this._data[this._count] = undefined;
-
- return ret;
-};
-
-FixedArray.prototype.fastRemove = function fastRemove (idx) {
- if (idx >= this._count) {
- return;
- }
-
- var last = this._count - 1;
- this._data[idx] = this._data[last];
- this._data[last] = undefined;
- this._count -= 1;
-};
-
-FixedArray.prototype.indexOf = function indexOf (val) {
- var idx = this._data.indexOf(val);
- if (idx >= this._count) {
- return -1;
- }
-
- return idx;
-};
-
-FixedArray.prototype.sort = function sort$1 (cmp) {
- return sort(this._data, 0, this._count, cmp);
-};
-
-Object.defineProperties( FixedArray.prototype, prototypeAccessors$7 );
-
-var Pool = function Pool(fn, size) {
- var this$1 = this;
-
- this._fn = fn;
- this._idx = size - 1;
- this._frees = new Array(size);
-
- for (var i = 0; i < size; ++i) {
- this$1._frees[i] = fn();
- }
-};
-
-Pool.prototype._expand = function _expand (size) {
- var this$1 = this;
-
- var old = this._frees;
- this._frees = new Array(size);
-
- var len = size - old.length;
- for (var i = 0; i < len; ++i) {
- this$1._frees[i] = this$1._fn();
- }
-
- for (var i$1 = len, j = 0; i$1 < size; ++i$1, ++j) {
- this$1._frees[i$1] = old[j];
- }
-
- this._idx += len;
-};
-
-Pool.prototype.alloc = function alloc () {
- // create some more space (expand by 20%, minimum 1)
- if (this._idx < 0) {
- this._expand(Math.round(this._frees.length * 1.2) + 1);
- }
-
- var ret = this._frees[this._idx];
- this._frees[this._idx] = null;
- --this._idx;
-
- return ret;
-};
-
-Pool.prototype.free = function free (obj) {
- ++this._idx;
- this._frees[this._idx] = obj;
-};
-
-// NOTE: you must have `_prev` and `_next` field in the object returns by `fn`
-
-var LinkedArray = function LinkedArray(fn, size) {
- this._fn = fn;
- this._count = 0;
- this._head = null;
- this._tail = null;
-
- this._pool = new Pool(fn, size);
-};
-
-var prototypeAccessors$8 = { head: { configurable: true },tail: { configurable: true },length: { configurable: true } };
-
-prototypeAccessors$8.head.get = function () {
- return this._head;
-};
-
-prototypeAccessors$8.tail.get = function () {
- return this._tail;
-};
-
-prototypeAccessors$8.length.get = function () {
- return this._count;
-};
-
-LinkedArray.prototype.add = function add () {
- var node = this._pool.alloc();
-
- if (!this._tail) {
- this._head = node;
- } else {
- this._tail._next = node;
- node._prev = this._tail;
- }
- this._tail = node;
- this._count += 1;
-
- return node;
-};
-
-LinkedArray.prototype.remove = function remove (node) {
- if (node._prev) {
- node._prev._next = node._next;
- } else {
- this._head = node._next;
- }
-
- if (node._next) {
- node._next._prev = node._prev;
- } else {
- this._tail = node._prev;
- }
-
- node._next = null;
- node._prev = null;
- this._pool.free(node);
- this._count -= 1;
-};
-
-LinkedArray.prototype.forEach = function forEach (fn, binder) {
- var this$1 = this;
-
- var cursor = this._head;
- if (!cursor) {
- return;
- }
-
- if (binder) {
- fn = fn.bind(binder);
- }
-
- var idx = 0;
- var next = cursor;
-
- while (cursor) {
- next = cursor._next;
- fn(cursor, idx, this$1);
-
- cursor = next;
- ++idx;
- }
-};
-
-Object.defineProperties( LinkedArray.prototype, prototypeAccessors$8 );
-
-var RecyclePool = function RecyclePool(fn, size) {
- var this$1 = this;
-
- this._fn = fn;
- this._count = 0;
- this._data = new Array(size);
-
- for (var i = 0; i < size; ++i) {
- this$1._data[i] = fn();
- }
-};
-
-var prototypeAccessors$9 = { length: { configurable: true },data: { configurable: true } };
-
-prototypeAccessors$9.length.get = function () {
- return this._count;
-};
-
-prototypeAccessors$9.data.get = function () {
- return this._data;
-};
-
-RecyclePool.prototype.reset = function reset () {
- this._count = 0;
-};
-
-RecyclePool.prototype.resize = function resize (size) {
- var this$1 = this;
-
- if (size > this._data.length) {
- for (var i = this._data.length; i < size; ++i) {
- this$1._data[i] = this$1._fn();
- }
- }
-};
-
-RecyclePool.prototype.add = function add () {
- if (this._count >= this._data.length) {
- this.resize(this._data.length * 2);
- }
-
- return this._data[this._count++];
-};
-
-RecyclePool.prototype.remove = function remove (idx) {
- if (idx >= this._count) {
- return;
- }
-
- var last = this._count - 1;
- var tmp = this._data[idx];
- this._data[idx] = this._data[last];
- this._data[last] = tmp;
- this._count -= 1;
-};
-
-RecyclePool.prototype.sort = function sort$1 (cmp) {
- return sort(this._data, 0, this._count, cmp);
-};
-
-Object.defineProperties( RecyclePool.prototype, prototypeAccessors$9 );
-
-var _bufferPools = Array(8);
-for (var i = 0; i < 8; ++i) {
- _bufferPools[i] = [];
-}
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var Scene = function Scene() {
- this._lights = new FixedArray(16);
- this._models = new FixedArray(16);
- this._cameras = new FixedArray(16);
- this._debugCamera = null;
-
- // NOTE: we don't use pool for views (because it's less changed and it doesn't have poolID)
- this._views = [];
-};
-
-Scene.prototype._add = function _add (pool, item) {
- if (item._poolID !== -1) {
- return;
- }
-
- pool.push(item);
- item._poolID = pool.length - 1;
-};
-
-Scene.prototype._remove = function _remove (pool, item) {
- if (item._poolID === -1) {
- return;
- }
-
- pool.data[pool.length-1]._poolID = item._poolID;
- pool.fastRemove(item._poolID);
- item._poolID = -1;
-};
-
-Scene.prototype.reset = function reset () {
- var this$1 = this;
-
- for (var i = 0; i < this._models.length; ++i) {
- var model = this$1._models.data[i];
- model._cullingMask = -1;
- }
-};
-
-Scene.prototype.setDebugCamera = function setDebugCamera (cam) {
- this._debugCamera = cam;
-};
-
-// camera
-
-Scene.prototype.getCameraCount = function getCameraCount () {
- return this._cameras.length;
-};
-
-Scene.prototype.getCamera = function getCamera (idx) {
- return this._cameras.data[idx];
-};
-
-Scene.prototype.addCamera = function addCamera (camera) {
- this._add(this._cameras, camera);
-};
-
-Scene.prototype.removeCamera = function removeCamera (camera) {
- this._remove(this._cameras, camera);
-};
-
-// model
-
-Scene.prototype.getModelCount = function getModelCount () {
- return this._models.length;
-};
-
-Scene.prototype.getModel = function getModel (idx) {
- return this._models.data[idx];
-};
-
-Scene.prototype.addModel = function addModel (model) {
- this._add(this._models, model);
-};
-
-Scene.prototype.removeModel = function removeModel (model) {
- this._remove(this._models, model);
-};
-
-// light
-
-Scene.prototype.getLightCount = function getLightCount () {
- return this._lights.length;
-};
-
-Scene.prototype.getLight = function getLight (idx) {
- return this._lights.data[idx];
-};
-
-Scene.prototype.addLight = function addLight (light) {
- this._add(this._lights, light);
-};
-
-Scene.prototype.removeLight = function removeLight (light) {
- this._remove(this._lights, light);
-};
-
-// view
-
-Scene.prototype.addView = function addView (view) {
- if (this._views.indexOf(view) === -1) {
- this._views.push(view);
- }
-};
-
-Scene.prototype.removeView = function removeView (view) {
- var idx = this._views.indexOf(view);
- if (idx !== -1) {
- this._views.splice(idx, 1);
- }
-};
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var _shdID = 0;
-
-function _generateDefines(defs) {
- var defines = [];
- for (var def in defs) {
- if (defs[def] === true) {
- defines.push(("#define " + def));
- }
- }
- return defines.join('\n');
-}
-
-function _replaceMacroNums(string, defs) {
- var cache = {};
- var tmp = string;
- for (var def in defs) {
- if (Number.isInteger(defs[def])) {
- cache[def] = defs[def];
- }
- }
- for (var def$1 in cache) {
- var reg = new RegExp(def$1, 'g');
- tmp = tmp.replace(reg, cache[def$1]);
- }
- return tmp;
-}
-
-function _unrollLoops(string) {
- var pattern = /#pragma for (\w+) in range\(\s*(\d+)\s*,\s*(\d+)\s*\)([\s\S]+?)#pragma endFor/g;
- function replace(match, index, begin, end, snippet) {
- var unroll = '';
- var parsedBegin = parseInt(begin);
- var parsedEnd = parseInt(end);
- if (parsedBegin.isNaN || parsedEnd.isNaN) {
- console.error('Unroll For Loops Error: begin and end of range must be an int num.');
- }
- for (var i = parsedBegin; i < parsedEnd; ++i) {
- unroll += snippet.replace(new RegExp(("{" + index + "}"), 'g'), i);
- }
- return unroll;
- }
- return string.replace(pattern, replace);
-}
-
-var ProgramLib = function ProgramLib(device, templates, chunks) {
- var this$1 = this;
- if ( templates === void 0 ) templates = [];
- if ( chunks === void 0 ) chunks = {};
-
- this._device = device;
- this._precision = "precision highp float;\n";
-
- // register templates
- this._templates = {};
- for (var i = 0; i < templates.length; ++i) {
- var tmpl = templates[i];
- this$1.define(tmpl.name, tmpl.vert, tmpl.frag, tmpl.defines);
- }
-
- // register chunks
- this._chunks = {};
- Object.assign(this._chunks, chunks);
-
- this._cache = {};
-};
-
-/**
- * @param {string} name
- * @param {string} template
- * @param {Array} options
- *
- * @example:
- * programLib.define('foobar', vertTmpl, fragTmpl, [
- * { name: 'shadow' },
- * { name: 'lightCount', min: 1, max: 4 }
- * ]);
- */
-ProgramLib.prototype.define = function define (name, vert, frag, defines) {
- if (this._templates[name]) {
- console.warn(("Failed to define shader " + name + ": already exists."));
- return;
- }
-
- var id = ++_shdID;
-
- // calculate option mask offset
- var offset = 0;
- var loop = function ( i ) {
- var def = defines[i];
- def._offset = offset;
-
- var cnt = 1;
-
- if (def.min !== undefined && def.max !== undefined) {
- cnt = Math.ceil((def.max - def.min) * 0.5);
-
- def._map = function (value) {
- return (value - this._min) << def._offset;
- }.bind(def);
- } else {
- def._map = function (value) {
- if (value) {
- return 1 << def._offset;
- }
- return 0;
- }.bind(def);
- }
-
- offset += cnt;
-
- def._offset = offset;
- };
-
- for (var i = 0; i < defines.length; ++i) loop( i );
-
- vert = this._precision + vert;
- frag = this._precision + frag;
-
- // store it
- this._templates[name] = {
- id: id,
- name: name,
- vert: vert,
- frag: frag,
- defines: defines
- };
-};
-
-/**
- * @param {string} name
- * @param {Object} options
- */
-ProgramLib.prototype.getKey = function getKey (name, defines) {
- var tmpl = this._templates[name];
- var key = 0;
- for (var i = 0; i < tmpl.defines.length; ++i) {
- var tmplDefs = tmpl.defines[i];
- var value = defines[tmplDefs.name];
- if (value === undefined) {
- continue;
- }
-
- key |= tmplDefs._map(value);
- }
-
- return key << 8 | tmpl.id;
-};
-
-/**
- * @param {string} name
- * @param {Object} options
- */
-ProgramLib.prototype.getProgram = function getProgram (name, defines) {
- var key = this.getKey(name, defines);
- var program = this._cache[key];
- if (program) {
- return program;
- }
-
- // get template
- var tmpl = this._templates[name];
- var customDef = _generateDefines(defines) + '\n';
- var vert = _replaceMacroNums(tmpl.vert, defines);
- vert = customDef + _unrollLoops(vert);
- var frag = _replaceMacroNums(tmpl.frag, defines);
- frag = customDef + _unrollLoops(frag);
-
- program = new gfx.Program(this._device, {
- vert: vert,
- frag: frag
- });
- program.link();
- this._cache[key] = program;
-
- return program;
-};
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var _m3_tmp$1 = mat3.create();
-var _m4_tmp$2 = mat4.create();
-
-var _stageInfos = new RecyclePool(function () {
- return {
- stage: null,
- items: null,
- };
-}, 8);
-
-var _float2_pool = new RecyclePool(function () {
- return new Float32Array(2);
-}, 8);
-
-var _float3_pool = new RecyclePool(function () {
- return new Float32Array(3);
-}, 8);
-
-var _float4_pool = new RecyclePool(function () {
- return new Float32Array(4);
-}, 8);
-
-var _float9_pool = new RecyclePool(function () {
- return new Float32Array(9);
-}, 8);
-
-var _float16_pool = new RecyclePool(function () {
- return new Float32Array(16);
-}, 8);
-
-var _float64_pool = new RecyclePool(function () {
- return new Float32Array(64);
-}, 8);
-
-var _int2_pool = new RecyclePool(function () {
- return new Int32Array(2);
-}, 8);
-
-var _int3_pool = new RecyclePool(function () {
- return new Int32Array(3);
-}, 8);
-
-var _int4_pool = new RecyclePool(function () {
- return new Int32Array(4);
-}, 8);
-
-var _int64_pool = new RecyclePool(function () {
- return new Int32Array(64);
-}, 8);
-
-var _type2uniformValue = {};
-_type2uniformValue[enums.PARAM_INT] = function (value) {
- return value;
- };
-_type2uniformValue[enums.PARAM_INT2] = function (value) {
- return vec2.array(_int2_pool.add(), value);
- };
-_type2uniformValue[enums.PARAM_INT3] = function (value) {
- return vec3.array(_int3_pool.add(), value);
- };
-_type2uniformValue[enums.PARAM_INT4] = function (value) {
- return vec4.array(_int4_pool.add(), value);
- };
-_type2uniformValue[enums.PARAM_FLOAT] = function (value) {
- return value;
- };
-_type2uniformValue[enums.PARAM_FLOAT2] = function (value) {
- return vec2.array(_float2_pool.add(), value);
- };
-_type2uniformValue[enums.PARAM_FLOAT3] = function (value) {
- return vec3.array(_float3_pool.add(), value);
- };
-_type2uniformValue[enums.PARAM_FLOAT4] = function (value) {
- return vec4.array(_float4_pool.add(), value);
- };
-_type2uniformValue[enums.PARAM_COLOR3] = function (value) {
- return color3.array(_float3_pool.add(), value);
- };
-_type2uniformValue[enums.PARAM_COLOR4] = function (value) {
- return color4.array(_float4_pool.add(), value);
- };
-_type2uniformValue[enums.PARAM_MAT2] = function (value) {
- return mat2.array(_float4_pool.add(), value);
- };
-_type2uniformValue[enums.PARAM_MAT3] = function (value) {
- return mat3.array(_float9_pool.add(), value);
- };
-_type2uniformValue[enums.PARAM_MAT4] = function (value) {
- return mat4.array(_float16_pool.add(), value);
- };
-
-var _type2uniformArrayValue = {};
-_type2uniformArrayValue[enums.PARAM_INT] = {
- func: function func (values) {
- var result = _int64_pool.add();
- for (var i = 0; i < values.length; ++i) {
- result[i] = values[i];
- }
- return result;
- },
- size: 1,
- };
-_type2uniformArrayValue[enums.PARAM_INT2] = {
- func: function func (values) {
- var result = _int64_pool.add();
- for (var i = 0; i < values.length; ++i) {
- result[2 * i] = values[i].x;
- result[2 * i + 1] = values[i].y;
- }
- return result;
- },
- size: 2,
- };
-_type2uniformArrayValue[enums.PARAM_INT3] = {
- func: undefined,
- size: 3,
- };
-_type2uniformArrayValue[enums.PARAM_INT4] = {
- func: function func (values) {
- var result = _int64_pool.add();
- for (var i = 0; i < values.length; ++i) {
- var v = values[i];
- result[4 * i] = v.x;
- result[4 * i + 1] = v.y;
- result[4 * i + 2] = v.z;
- result[4 * i + 3] = v.w;
- }
- return result;
- },
- size: 4,
- };
-_type2uniformArrayValue[enums.PARAM_FLOAT] = {
- func: function func (values) {
- var result = _float64_pool.add();
- for (var i = 0; i < values.length; ++i) {
- result[i] = values[i];
- }
- return result;
- },
- size: 1
- };
-_type2uniformArrayValue[enums.PARAM_FLOAT2] = {
- func: function func (values) {
- var result = _float64_pool.add();
- for (var i = 0; i < values.length; ++i) {
- result[2 * i] = values[i].x;
- result[2 * i + 1] = values[i].y;
- }
- return result;
- },
- size: 2,
- };
-_type2uniformArrayValue[enums.PARAM_FLOAT3] = {
- func: undefined,
- size: 3,
- };
-_type2uniformArrayValue[enums.PARAM_FLOAT4] = {
- func: function func (values) {
- var result = _float64_pool.add();
- for (var i = 0; i < values.length; ++i) {
- var v = values[i];
- result[4 * i] = v.x;
- result[4 * i + 1] = v.y;
- result[4 * i + 2] = v.z;
- result[4 * i + 3] = v.w;
- }
- return result;
- },
- size: 4,
- };
-_type2uniformArrayValue[enums.PARAM_COLOR3] = {
- func: undefined,
- size: 3,
- };
-_type2uniformArrayValue[enums.PARAM_COLOR4] = {
- func: function func (values) {
- var result = _float64_pool.add();
- for (var i = 0; i < values.length; ++i) {
- var v = values[i];
- result[4 * i] = v.r;
- result[4 * i + 1] = v.g;
- result[4 * i + 2] = v.b;
- result[4 * i + 3] = v.a;
- }
- return result;
- },
- size: 4,
- };
-_type2uniformArrayValue[enums.PARAM_MAT2] = {
- func: function func (values) {
- var result = _float64_pool.add();
- for (var i = 0; i < values.length; ++i) {
- var v = values[i];
- result[4 * i] = v.m00;
- result[4 * i + 1] = v.m01;
- result[4 * i + 2] = v.m02;
- result[4 * i + 3] = v.m03;
- }
- return result;
- },
- size: 4
- };
-_type2uniformArrayValue[enums.PARAM_MAT3] = {
- func: undefined,
- size: 9
- };
-_type2uniformArrayValue[enums.PARAM_MAT4] = {
- func: function func (values) {
- var result = _float64_pool.add();
- for (var i = 0; i < values.length; ++i) {
- var v = values[i];
- result[16 * i] = v.m00;
- result[16 * i + 1] = v.m01;
- result[16 * i + 2] = v.m02;
- result[16 * i + 3] = v.m03;
- result[16 * i + 4] = v.m04;
- result[16 * i + 5] = v.m05;
- result[16 * i + 6] = v.m06;
- result[16 * i + 7] = v.m07;
- result[16 * i + 8] = v.m08;
- result[16 * i + 9] = v.m09;
- result[16 * i + 10] = v.m10;
- result[16 * i + 11] = v.m11;
- result[16 * i + 12] = v.m12;
- result[16 * i + 13] = v.m13;
- result[16 * i + 14] = v.m14;
- result[16 * i + 15] = v.m15;
- }
- return result;
- },
- size: 16
- };
-
-var Base = function Base(device, opts) {
- var obj;
-
- this._device = device;
- this._programLib = new ProgramLib(device, opts.programTemplates, opts.programChunks);
- this._opts = opts;
- this._type2defaultValue = ( obj = {}, obj[enums.PARAM_INT] = 0, obj[enums.PARAM_INT2] = vec2.new(0, 0), obj[enums.PARAM_INT3] = vec3.new(0, 0, 0), obj[enums.PARAM_INT4] = vec4.new(0, 0, 0, 0), obj[enums.PARAM_FLOAT] = 0.0, obj[enums.PARAM_FLOAT2] = vec2.new(0, 0), obj[enums.PARAM_FLOAT3] = vec3.new(0, 0, 0), obj[enums.PARAM_FLOAT4] = vec4.new(0, 0, 0, 0), obj[enums.PARAM_COLOR3] = color3.new(0, 0, 0), obj[enums.PARAM_COLOR4] = color4.new(0, 0, 0, 1), obj[enums.PARAM_MAT2] = mat2.create(), obj[enums.PARAM_MAT3] = mat3.create(), obj[enums.PARAM_MAT4] = mat4.create(), obj[enums.PARAM_TEXTURE_2D] = opts.defaultTexture, obj[enums.PARAM_TEXTURE_CUBE] = opts.defaultTextureCube, obj);
- this._stage2fn = {};
- this._usedTextureUnits = 0;
-
- this._viewPools = new RecyclePool(function () {
- return new View();
- }, 8);
-
- this._drawItemsPools = new RecyclePool(function () {
- return {
- model: null,
- node: null,
- ia: null,
- effect: null,
- defines: null,
- };
- }, 100);
-
- this._stageItemsPools = new RecyclePool(function () {
- return new RecyclePool(function () {
- return {
- model: null,
- node: null,
- ia: null,
- effect: null,
- defines: null,
- technique: null,
- sortKey: -1,
- };
- }, 100);
- }, 16);
-};
-
-Base.prototype._resetTextuerUnit = function _resetTextuerUnit () {
- this._usedTextureUnits = 0;
-};
-
-Base.prototype._allocTextuerUnit = function _allocTextuerUnit () {
- var device = this._device;
-
- var unit = this._usedTextureUnits;
- if (unit >= device._caps.maxTextureUnits) {
- console.warn(("Trying to use " + unit + " texture units while this GPU supports only " + (device._caps.maxTextureUnits)));
- }
-
- this._usedTextureUnits += 1;
- return unit;
-};
-
-Base.prototype._registerStage = function _registerStage (name, fn) {
- this._stage2fn[name] = fn;
-};
-
-Base.prototype._reset = function _reset () {
- this._viewPools.reset();
- this._stageItemsPools.reset();
-};
-
-Base.prototype._requestView = function _requestView () {
- return this._viewPools.add();
-};
-
-Base.prototype._render = function _render (view, scene) {
- var this$1 = this;
-
- var device = this._device;
-
- // setup framebuffer
- device.setFrameBuffer(view._framebuffer);
-
- // setup viewport
- device.setViewport(
- view._rect.x,
- view._rect.y,
- view._rect.w,
- view._rect.h
- );
-
- // setup clear
- var clearOpts = {};
- if (view._clearFlags & enums.CLEAR_COLOR) {
- clearOpts.color = [
- view._color.r,
- view._color.g,
- view._color.b,
- view._color.a
- ];
- }
- if (view._clearFlags & enums.CLEAR_DEPTH) {
- clearOpts.depth = view._depth;
- }
- if (view._clearFlags & enums.CLEAR_STENCIL) {
- clearOpts.stencil = view._stencil;
- }
- device.clear(clearOpts);
-
- // get all draw items
- this._drawItemsPools.reset();
-
- for (var i = 0; i < scene._models.length; ++i) {
- var model = scene._models.data[i];
-
- // filter model by view
- if ((model._cullingMask & view._cullingMask) === 0) {
- continue;
- }
-
- for (var m = 0; m < model.drawItemCount; ++m) {
- var drawItem = this$1._drawItemsPools.add();
- model.extractDrawItem(drawItem, m);
- }
- }
-
- // TODO: update frustum
- // TODO: visbility test
- // frustum.update(view._viewProj);
-
- // dispatch draw items to different stage
- _stageInfos.reset();
-
- for (var i$1 = 0; i$1 < view._stages.length; ++i$1) {
- var stage = view._stages[i$1];
- var stageItems = this$1._stageItemsPools.add();
- stageItems.reset();
-
- for (var j = 0; j < this._drawItemsPools.length; ++j) {
- var drawItem$1 = this$1._drawItemsPools.data[j];
- var tech = drawItem$1.effect.getTechnique(stage);
-
- if (tech) {
- var stageItem = stageItems.add();
- stageItem.model = drawItem$1.model;
- stageItem.node = drawItem$1.node;
- stageItem.ia = drawItem$1.ia;
- stageItem.effect = drawItem$1.effect;
- stageItem.defines = drawItem$1.defines;
- stageItem.technique = tech;
- stageItem.sortKey = -1;
- }
- }
-
- var stageInfo = _stageInfos.add();
- stageInfo.stage = stage;
- stageInfo.items = stageItems;
- }
-
- // render stages
- for (var i$2 = 0; i$2 < _stageInfos.length; ++i$2) {
- var info = _stageInfos.data[i$2];
- var fn = this$1._stage2fn[info.stage];
-
- fn(view, info.items);
- }
-};
-
-Base.prototype._draw = function _draw (item) {
- var this$1 = this;
-
- var device = this._device;
- var programLib = this._programLib;
- var node = item.node;
- var ia = item.ia;
- var effect = item.effect;
- var technique = item.technique;
- var defines = item.defines;
-
- // reset the pool
- // NOTE: we can use drawCounter optimize this
- // TODO: should be configurable
- _float2_pool.reset();
- _float3_pool.reset();
- _float4_pool.reset();
- _float9_pool.reset();
- _float16_pool.reset();
- _float64_pool.reset();
- _int2_pool.reset();
- _int3_pool.reset();
- _int4_pool.reset();
- _int64_pool.reset();
-
- // set common uniforms
- // TODO: try commit this depends on effect
- // {
- node.getWorldMatrix(_m4_tmp$2);
- device.setUniform('model', mat4.array(_float16_pool.add(), _m4_tmp$2));
-
- var inverse = mat3.invert(_m3_tmp$1, mat3.fromMat4(_m3_tmp$1, _m4_tmp$2));
- if (inverse) {
- mat3.transpose(_m3_tmp$1, inverse);
- device.setUniform('normalMatrix', mat3.array(_float9_pool.add(), _m3_tmp$1));
- }
- // }
-
- // set technique uniforms
- for (var i = 0; i < technique._parameters.length; ++i) {
- var prop = technique._parameters[i];
- var param = effect.getProperty(prop.name);
-
- if (param === undefined) {
- param = prop.val;
- }
-
- if (param === undefined) {
- param = this$1._type2defaultValue[prop.type];
- }
-
- if (param === undefined) {
- console.warn(("Failed to set technique property " + (prop.name) + ", value not found."));
- continue;
- }
-
- if (
- prop.type === enums.PARAM_TEXTURE_2D ||
- prop.type === enums.PARAM_TEXTURE_CUBE
- ) {
- if (prop.size !== undefined) {
- if (prop.size !== param.length) {
- console.error(("The length of texture array (" + (param.length) + ") is not corrent(expect " + (prop.size) + ")."));
- continue;
- }
- var slots = _int64_pool.add();
- for (var index = 0; index < param.length; ++index) {
- slots[index] = this$1._allocTextuerUnit();
- }
- device.setTextureArray(prop.name, param, slots);
- } else {
- device.setTexture(prop.name, param, this$1._allocTextuerUnit());
- }
- } else {
- var convertedValue = (void 0);
- if (param instanceof Float32Array || param instanceof Int32Array) {
- convertedValue = param;
- }
- else if (prop.size !== undefined) {
- var convertArray = _type2uniformArrayValue[prop.type];
- if (convertArray.func === undefined) {
- console.error('Uniform array of color3/int3/float3/mat3 can not be supportted!');
- continue;
- }
- if (prop.size * convertArray.size > 64) {
- console.error('Uniform array is too long!');
- continue;
- }
- convertedValue = convertArray.func(param);
- } else {
- var convertFn = _type2uniformValue[prop.type];
- convertedValue = convertFn(param);
- }
- device.setUniform(prop.name, convertedValue);
- }
- }
-
- // for each pass
- for (var i$1 = 0; i$1 < technique._passes.length; ++i$1) {
- var pass = technique._passes[i$1];
- var count = ia.getPrimitiveCount();
-
- // set vertex buffer
- device.setVertexBuffer(0, ia._vertexBuffer);
-
- // set index buffer
- if (ia._indexBuffer) {
- device.setIndexBuffer(ia._indexBuffer);
- }
-
- // set primitive type
- device.setPrimitiveType(ia._primitiveType);
-
- // set program
- var program = programLib.getProgram(pass._programName, defines);
- device.setProgram(program);
-
- // cull mode
- device.setCullMode(pass._cullMode);
-
- // blend
- if (pass._blend) {
- device.enableBlend();
- device.setBlendFuncSep(
- pass._blendSrc,
- pass._blendDst,
- pass._blendSrcAlpha,
- pass._blendDstAlpha
- );
- device.setBlendEqSep(
- pass._blendEq,
- pass._blendAlphaEq
- );
- device.setBlendColor32(pass._blendColor);
- }
-
- // depth test & write
- if (pass._depthTest) {
- device.enableDepthTest();
- device.setDepthFunc(pass._depthFunc);
- }
- if (pass._depthWrite) {
- device.enableDepthWrite();
- }
-
- // stencil
- if (pass._stencilTest) {
- device.enableStencilTest();
-
- // front
- device.setStencilFuncFront(
- pass._stencilFuncFront,
- pass._stencilRefFront,
- pass._stencilMaskFront
- );
- device.setStencilOpFront(
- pass._stencilFailOpFront,
- pass._stencilZFailOpFront,
- pass._stencilZPassOpFront,
- pass._stencilWriteMaskFront
- );
-
- // back
- device.setStencilFuncBack(
- pass._stencilFuncBack,
- pass._stencilRefBack,
- pass._stencilMaskBack
- );
- device.setStencilOpBack(
- pass._stencilFailOpBack,
- pass._stencilZFailOpBack,
- pass._stencilZPassOpBack,
- pass._stencilWriteMaskBack
- );
- }
-
- // draw pass
- device.draw(ia._start, count);
-
- this$1._resetTextuerUnit();
- }
-};
-
-var renderer = {
- // config
- addStage: config.addStage,
-
- // utils
- createIA: createIA,
-
- // classes
- Pass: Pass,
- Technique: Technique,
- Effect: Effect,
- InputAssembler: InputAssembler,
- View: View,
-
- Light: Light,
- Camera: Camera,
- Model: Model,
- Scene: Scene,
-
- Base: Base,
- ProgramLib: ProgramLib,
-};
-Object.assign(renderer, enums);
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var _a16_view = new Float32Array(16);
-var _a16_proj = new Float32Array(16);
-var _a16_viewProj = new Float32Array(16);
-
-var ForwardRenderer = (function (superclass) {
- function ForwardRenderer (device, builtin) {
- superclass.call(this, device, builtin);
- this._registerStage('transparent', this._transparentStage.bind(this));
- }
-
- if ( superclass ) ForwardRenderer.__proto__ = superclass;
- ForwardRenderer.prototype = Object.create( superclass && superclass.prototype );
- ForwardRenderer.prototype.constructor = ForwardRenderer;
-
- ForwardRenderer.prototype.reset = function reset () {
- this._reset();
- };
-
- ForwardRenderer.prototype.render = function render (scene) {
- var this$1 = this;
-
- this._reset();
-
- scene._cameras.sort(function (a, b) {
- if (a._sortDepth > b._sortDepth) { return 1; }
- else if (a._sortDepth < b._sortDepth) { return -1; }
- else { return 0; }
- });
-
- for (var i = 0; i < scene._cameras.length; ++i) {
- var camera = scene._cameras.data[i];
-
- // reset camera pollID after sort cameras
- camera._poolID = i;
-
- this$1.renderCamera(camera, scene);
- }
- };
-
- ForwardRenderer.prototype.renderCamera = function renderCamera (camera, scene) {
- var canvas = this._device._gl.canvas;
-
- var view = camera.view;
- var dirty = camera.dirty;
- if (!view) {
- view = this._requestView();
- dirty = true;
- }
- if (dirty) {
- var width = canvas.width;
- var height = canvas.height;
- if (camera._framebuffer) {
- width = camera._framebuffer._width;
- height = camera._framebuffer._height;
- }
- camera.extractView(view, width, height);
- }
- this._render(view, scene);
- };
-
- ForwardRenderer.prototype._transparentStage = function _transparentStage (view, items) {
- var this$1 = this;
-
- // update uniforms
- this._device.setUniform('view', mat4.array(_a16_view, view._matView));
- this._device.setUniform('proj', mat4.array(_a16_proj, view._matProj));
- this._device.setUniform('viewProj', mat4.array(_a16_viewProj, view._matViewProj));
-
- // draw it
- for (var i = 0; i < items.length; ++i) {
- var item = items.data[i];
- this$1._draw(item);
- }
- };
-
- return ForwardRenderer;
-}(renderer.Base));
-
-var chunks = {
- 'skinning.vert': '\nattribute vec4 a_weights;\nattribute vec4 a_joints;\n#ifdef useJointsTexture\nuniform sampler2D u_jointsTexture;\nuniform float u_jointsTextureSize;\nmat4 getBoneMatrix(const in float i) {\n float size = u_jointsTextureSize;\n float j = i * 4.0;\n float x = mod(j, size);\n float y = floor(j / size);\n float dx = 1.0 / size;\n float dy = 1.0 / size;\n y = dy * (y + 0.5);\n vec4 v1 = texture2D(u_jointsTexture, vec2(dx * (x + 0.5), y));\n vec4 v2 = texture2D(u_jointsTexture, vec2(dx * (x + 1.5), y));\n vec4 v3 = texture2D(u_jointsTexture, vec2(dx * (x + 2.5), y));\n vec4 v4 = texture2D(u_jointsTexture, vec2(dx * (x + 3.5), y));\n return mat4(v1, v2, v3, v4);\n}\n#else\nuniform mat4 u_jointMatrices[64];\nmat4 getBoneMatrix(const in float i) {\n return u_jointMatrices[int(i)];\n}\n#endif\nmat4 skinMatrix() {\n return\n getBoneMatrix(a_joints.x) * a_weights.x +\n getBoneMatrix(a_joints.y) * a_weights.y +\n getBoneMatrix(a_joints.z) * a_weights.z +\n getBoneMatrix(a_joints.w) * a_weights.w\n ;\n}',
-};
-
-var templates = [
- {
- name: 'gray_sprite',
- vert: '\n \nuniform mat4 viewProj;\nattribute vec3 a_position;\nattribute mediump vec2 a_uv0;\nvarying mediump vec2 uv0;\nvoid main () {\n vec4 pos = viewProj * vec4(a_position, 1);\n gl_Position = pos;\n uv0 = a_uv0;\n}',
- frag: '\n \nuniform sampler2D texture;\nvarying mediump vec2 uv0;\nuniform lowp vec4 color;\nvoid main () {\n vec4 c = color * texture2D(texture, uv0);\n float gray = 0.2126*c.r + 0.7152*c.g + 0.0722*c.b;\n gl_FragColor = vec4(gray, gray, gray, c.a);\n}',
- defines: [
- ],
- },
- {
- name: 'mesh',
- vert: '\n \nuniform mat4 viewProj;\nattribute vec3 a_position;\n#ifdef useAttributeColor\n attribute vec4 a_color;\n varying vec4 v_color;\n#endif\n#ifdef useTexture\n attribute vec2 a_uv0;\n varying vec2 uv0;\n#endif\n#ifdef useModel\n uniform mat4 model;\n#endif\n#ifdef useSkinning\n \nattribute vec4 a_weights;\nattribute vec4 a_joints;\n#ifdef useJointsTexture\nuniform sampler2D u_jointsTexture;\nuniform float u_jointsTextureSize;\nmat4 getBoneMatrix(const in float i) {\n float size = u_jointsTextureSize;\n float j = i * 4.0;\n float x = mod(j, size);\n float y = floor(j / size);\n float dx = 1.0 / size;\n float dy = 1.0 / size;\n y = dy * (y + 0.5);\n vec4 v1 = texture2D(u_jointsTexture, vec2(dx * (x + 0.5), y));\n vec4 v2 = texture2D(u_jointsTexture, vec2(dx * (x + 1.5), y));\n vec4 v3 = texture2D(u_jointsTexture, vec2(dx * (x + 2.5), y));\n vec4 v4 = texture2D(u_jointsTexture, vec2(dx * (x + 3.5), y));\n return mat4(v1, v2, v3, v4);\n}\n#else\nuniform mat4 u_jointMatrices[64];\nmat4 getBoneMatrix(const in float i) {\n return u_jointMatrices[int(i)];\n}\n#endif\nmat4 skinMatrix() {\n return\n getBoneMatrix(a_joints.x) * a_weights.x +\n getBoneMatrix(a_joints.y) * a_weights.y +\n getBoneMatrix(a_joints.z) * a_weights.z +\n getBoneMatrix(a_joints.w) * a_weights.w\n ;\n}\n#endif\nvoid main () {\n mat4 mvp;\n #ifdef useModel\n mvp = viewProj * model;\n #else\n mvp = viewProj;\n #endif\n #ifdef useSkinning\n mvp = mvp * skinMatrix();\n #endif\n vec4 pos = mvp * vec4(a_position, 1);\n #ifdef useTexture\n uv0 = a_uv0;\n #endif\n #ifdef useAttributeColor\n v_color = a_color;\n #endif\n gl_Position = pos;\n}',
- frag: '\n \n#ifdef useTexture\n uniform sampler2D texture;\n varying vec2 uv0;\n#endif\n#ifdef useAttributeColor\n varying vec4 v_color;\n#endif\nuniform vec4 color;\nvoid main () {\n vec4 o = color;\n \n #ifdef useAttributeColor\n o *= v_color;\n #endif\n #ifdef useTexture\n o *= texture2D(texture, uv0);\n #endif\n gl_FragColor = o;\n}',
- defines: [
- { name: 'useTexture', },
- { name: 'useModel', },
- { name: 'useSkinning', },
- { name: 'useJointsTexture', },
- { name: 'useAttributeColor', } ],
- },
- {
- name: 'sprite',
- vert: '\n \nuniform mat4 viewProj;\n#ifdef use2DPos\nattribute vec2 a_position;\n#else\nattribute vec3 a_position;\n#endif\nattribute lowp vec4 a_color;\n#ifdef useModel\n uniform mat4 model;\n#endif\n#ifdef useTexture\n attribute mediump vec2 a_uv0;\n varying mediump vec2 uv0;\n#endif\n#ifndef useColor\nvarying lowp vec4 v_fragmentColor;\n#endif\nvoid main () {\n mat4 mvp;\n #ifdef useModel\n mvp = viewProj * model;\n #else\n mvp = viewProj;\n #endif\n #ifdef use2DPos\n vec4 pos = mvp * vec4(a_position, 0, 1);\n #else\n vec4 pos = mvp * vec4(a_position, 1);\n #endif\n #ifndef useColor\n v_fragmentColor = a_color;\n #endif\n #ifdef useTexture\n uv0 = a_uv0;\n #endif\n gl_Position = pos;\n}',
- frag: '\n \n#ifdef useTexture\n uniform sampler2D texture;\n varying mediump vec2 uv0;\n#endif\n#ifdef alphaTest\n uniform lowp float alphaThreshold;\n#endif\n#ifdef useColor\n uniform lowp vec4 color;\n#else\n varying lowp vec4 v_fragmentColor;\n#endif\nvoid main () {\n #ifdef useColor\n vec4 o = color;\n #else\n vec4 o = v_fragmentColor;\n #endif\n #ifdef useTexture\n o *= texture2D(texture, uv0);\n #endif\n #ifdef alphaTest\n if (o.a <= alphaThreshold)\n discard;\n #endif\n gl_FragColor = o;\n}',
- defines: [
- { name: 'useTexture', },
- { name: 'useModel', },
- { name: 'alphaTest', },
- { name: 'use2DPos', },
- { name: 'useColor', } ],
- } ];
-
-var shaders = {
- chunks: chunks,
- templates: templates
-};
-
-// Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
-
-/**
- * BaseRenderData is a core data abstraction for renderer, this is a abstract class.
- * An inherited render data type should define raw vertex datas.
- * User should also define the effect, vertex count and index count.
- */
-var BaseRenderData = function BaseRenderData () {
- this.material = null;
- this.vertexCount = 0;
- this.indiceCount = 0;
-};
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var _pool;
-var _dataPool = new Pool(function () {
- return {
- x: 0.0,
- y: 0.0,
- u: 0.0,
- v: 0.0,
- color: 0
- };
-}, 128);
-
-/**
- * RenderData is most widely used render data type.
- * It describes raw vertex data with a fixed data layout.
- * Each vertex is described by five property: x, y, u, v, color. The data layout might be extended in the future.
- * Vertex data objects are managed automatically by RenderData, user only need to set the dataLength property.
- * User can also define rendering index orders for the vertex list.
- */
-var RenderData = (function (BaseRenderData$$1) {
- function RenderData () {
- BaseRenderData$$1.call(this);
- this._data = [];
- this._indices = [];
-
- this._pivotX = 0;
- this._pivotY = 0;
- this._width = 0;
- this._height = 0;
-
- this.uvDirty = true;
- this.vertDirty = true;
- }
-
- if ( BaseRenderData$$1 ) RenderData.__proto__ = BaseRenderData$$1;
- RenderData.prototype = Object.create( BaseRenderData$$1 && BaseRenderData$$1.prototype );
- RenderData.prototype.constructor = RenderData;
-
- var prototypeAccessors = { type: { configurable: true },dataLength: { configurable: true } };
-
- prototypeAccessors.type.get = function () {
- return RenderData.type;
- };
-
- prototypeAccessors.dataLength.get = function () {
- return this._data.length;
- };
-
- prototypeAccessors.dataLength.set = function (length) {
- var data = this._data;
- if (data.length !== length) {
- // Free extra data
- for (var i = length; i < data.length; i++) {
- _dataPool.free(data[i]);
- }
- // Alloc needed data
- for (var i$1 = data.length; i$1 < length; i$1++) {
- data[i$1] = _dataPool.alloc();
- }
- data.length = length;
- }
- };
-
- RenderData.prototype.updateSizeNPivot = function updateSizeNPivot (width, height, pivotX, pivotY) {
- if (width !== this._width ||
- height !== this._height ||
- pivotX !== this._pivotX ||
- pivotY !== this._pivotY)
- {
- this._width = width;
- this._height = height;
- this._pivotX = pivotX;
- this._pivotY = pivotY;
- this.vertDirty = true;
- }
- };
-
- RenderData.alloc = function alloc () {
- return _pool.alloc();
- };
-
- RenderData.free = function free (data) {
- if (data instanceof RenderData) {
- for (var i = data.length-1; i > 0; i--) {
- _dataPool.free(data._data[i]);
- }
- data._data.length = 0;
- data._indices.length = 0;
- data.material = null;
- data.uvDirty = true;
- data.vertDirty = true;
- data.vertexCount = 0;
- data.indiceCount = 0;
- _pool.free(data);
- }
- };
-
- Object.defineProperties( RenderData.prototype, prototypeAccessors );
-
- return RenderData;
-}(BaseRenderData));
-
-RenderData.type = 'RenderData';
-
-_pool = new Pool(function () {
- return new RenderData();
-}, 32);
-
-// Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
-
-/**
- * IARenderData is user customized render data type, user should provide the entier input assembler.
- * IARenderData just defines a property `ia` for accessing the input assembler.
- * It doesn't manage memory so users should manage the memory of input assembler by themselves.
- */
-var IARenderData = (function (BaseRenderData$$1) {
- function IARenderData () {
- BaseRenderData$$1.call(this);
- this.ia = null;
- }
-
- if ( BaseRenderData$$1 ) IARenderData.__proto__ = BaseRenderData$$1;
- IARenderData.prototype = Object.create( BaseRenderData$$1 && BaseRenderData$$1.prototype );
- IARenderData.prototype.constructor = IARenderData;
-
- var prototypeAccessors = { type: { configurable: true } };
-
- prototypeAccessors.type.get = function () {
- return IARenderData.type;
- };
-
- Object.defineProperties( IARenderData.prototype, prototypeAccessors );
-
- return IARenderData;
-}(BaseRenderData));
-
-IARenderData.type = 'IARenderData';
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var Asset = function Asset(persist) {
- if ( persist === void 0 ) persist = true;
-
- this._loaded = false;
- this._persist = persist;
-};
-
-Asset.prototype.unload = function unload () {
- this._loaded = false;
-};
-
-Asset.prototype.reload = function reload () {
- // TODO
-};
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var Texture$2 = (function (Asset$$1) {
- function Texture(persist) {
- if ( persist === void 0 ) persist = true;
-
- Asset$$1.call(this, persist);
-
- this._texture = null;
- }
-
- if ( Asset$$1 ) Texture.__proto__ = Asset$$1;
- Texture.prototype = Object.create( Asset$$1 && Asset$$1.prototype );
- Texture.prototype.constructor = Texture;
-
- Texture.prototype.getImpl = function getImpl () {
- return this._texture;
- };
-
- Texture.prototype.getId = function getId () {};
-
- Texture.prototype.destroy = function destroy () {
- this._texture && this._texture.destroy();
- };
-
- return Texture;
-}(Asset));
-
-/**
- * JS Implementation of MurmurHash2
- *
- * @author Gary Court
- * @see http://github.com/garycourt/murmurhash-js
- * @author Austin Appleby
- * @see http://sites.google.com/site/murmurhash/
- *
- * @param {string} str ASCII only
- * @param {number} seed Positive integer only
- * @return {number} 32-bit positive integer hash
- */
-
-function murmurhash2_32_gc(str, seed) {
- var
- l = str.length,
- h = seed ^ l,
- i = 0,
- k;
-
- while (l >= 4) {
- k =
- ((str.charCodeAt(i) & 0xff)) |
- ((str.charCodeAt(++i) & 0xff) << 8) |
- ((str.charCodeAt(++i) & 0xff) << 16) |
- ((str.charCodeAt(++i) & 0xff) << 24);
-
- k = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16));
- k ^= k >>> 24;
- k = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16));
-
- h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16)) ^ k;
-
- l -= 4;
- ++i;
- }
-
- switch (l) {
- case 3: h ^= (str.charCodeAt(i + 2) & 0xff) << 16;
- case 2: h ^= (str.charCodeAt(i + 1) & 0xff) << 8;
- case 1: h ^= (str.charCodeAt(i) & 0xff);
- h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16));
- }
-
- h ^= h >>> 13;
- h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16));
- h ^= h >>> 15;
-
- return h >>> 0;
-}
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-// function genHashCode (str) {
-// var hash = 0;
-// if (str.length == 0) {
-// return hash;
-// }
-// for (var i = 0; i < str.length; i++) {
-// var char = str.charCodeAt(i);
-// hash = ((hash<<5)-hash)+char;
-// hash = hash & hash; // Convert to 32bit integer
-// }
-// return hash;
-// }
-
-function serializeDefines (defines) {
- var str = '';
- for (var i = 0; i < defines.length; i++) {
- str += defines[i].name + defines[i].value;
- }
- return str;
-}
-
-function serializePass (pass) {
- var str = pass._programName + pass._cullMode;
- if (pass._blend) {
- str += pass._blendEq + pass._blendAlphaEq + pass._blendSrc + pass._blendDst
- + pass._blendSrcAlpha + pass._blendDstAlpha + pass._blendColor;
- }
- if (pass._depthTest) {
- str += pass._depthWrite + pass._depthFunc;
- }
- if (pass._stencilTest) {
- str += pass._stencilFuncFront + pass._stencilRefFront + pass._stencilMaskFront
- + pass._stencilFailOpFront + pass._stencilZFailOpFront + pass._stencilZPassOpFront
- + pass._stencilWriteMaskFront
- + pass._stencilFuncBack + pass._stencilRefBack + pass._stencilMaskBack
- + pass._stencilFailOpBack + pass._stencilZFailOpBack + pass._stencilZPassOpBack
- + pass._stencilWriteMaskBack;
- }
- return str;
-}
-
-function computeHash(material) {
- var effect = material._effect;
- var hashData = '';
- if (effect) {
- var i, j, techData, param, prop, propKey;
-
- // effect._defines
- hashData += serializeDefines(effect._defines);
- // effect._techniques
- for (i = 0; i < effect._techniques.length; i++) {
- techData = effect._techniques[i];
- // technique.stageIDs
- hashData += techData.stageIDs;
- // technique._layer
- // hashData += + techData._layer + "_";
- // technique.passes
- for (j = 0; j < techData.passes.length; j++) {
- hashData += serializePass(techData.passes[j]);
- }
- //technique._parameters
- for (j = 0; j < techData._parameters.length; j++) {
- param = techData._parameters[j];
- propKey = param.name;
- prop = effect._properties[propKey];
- if (!prop) {
- continue;
- }
- switch(param.type) {
- case renderer.PARAM_INT:
- case renderer.PARAM_FLOAT:
- hashData += prop + ';';
- break;
- case renderer.PARAM_INT2:
- case renderer.PARAM_FLOAT2:
- hashData += prop.x + ',' + prop.y + ';';
- break;
- case renderer.PARAM_INT4:
- case renderer.PARAM_FLOAT4:
- hashData += prop.x + ',' + prop.y + ',' + prop.z + ',' + prop.w + ';';
- break;
- case renderer.PARAM_COLOR4:
- hashData += prop.r + ',' + prop.g + ',' + prop.b + ',' + prop.a + ';';
- break;
- case renderer.PARAM_MAT2:
- hashData += prop.m00 + ',' + prop.m01 + ',' + prop.m02 + ',' + prop.m03 + ';';
- break;
- case renderer.PARAM_TEXTURE_2D:
- case renderer.PARAM_TEXTURE_CUBE:
- hashData += material._texIds[propKey] + ';';
- break;
- case renderer.PARAM_INT3:
- case renderer.PARAM_FLOAT3:
- case renderer.PARAM_COLOR3:
- case renderer.PARAM_MAT3:
- case renderer.PARAM_MAT4:
- hashData += JSON.stringify(prop) + ';';
- break;
- default:
- break;
- }
- }
- }
- }
- return hashData ? murmurhash2_32_gc(hashData, 666) : hashData;
-}
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var Material = (function (Asset$$1) {
- function Material(persist) {
- if ( persist === void 0 ) persist = false;
-
- Asset$$1.call(this, persist);
-
- this._effect = null; // renderer.Effect
- this._texIds = {}; // ids collected from texture defines
- this._hash = '';
- }
-
- if ( Asset$$1 ) Material.__proto__ = Asset$$1;
- Material.prototype = Object.create( Asset$$1 && Asset$$1.prototype );
- Material.prototype.constructor = Material;
-
- var prototypeAccessors = { hash: { configurable: true } };
-
- prototypeAccessors.hash.get = function () {
- return this._hash;
- };
-
- Material.prototype.updateHash = function updateHash (value) {
- this._hash = value || computeHash(this);
- };
-
- Object.defineProperties( Material.prototype, prototypeAccessors );
-
- return Material;
-}(Asset));
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var SpriteMaterial = (function (Material$$1) {
- function SpriteMaterial() {
- Material$$1.call(this, false);
-
- var pass = new renderer.Pass('sprite');
- pass.setDepth(false, false);
- pass.setCullMode(gfx.CULL_NONE);
- pass.setBlend(
- gfx.BLEND_FUNC_ADD,
- gfx.BLEND_SRC_ALPHA, gfx.BLEND_ONE_MINUS_SRC_ALPHA,
- gfx.BLEND_FUNC_ADD,
- gfx.BLEND_SRC_ALPHA, gfx.BLEND_ONE_MINUS_SRC_ALPHA
- );
-
- var mainTech = new renderer.Technique(
- ['transparent'],
- [
- { name: 'texture', type: renderer.PARAM_TEXTURE_2D },
- { name: 'color', type: renderer.PARAM_COLOR4 } ],
- [
- pass
- ]
- );
-
- this._color = {r: 1, g: 1, b: 1, a: 1};
- this._effect = new renderer.Effect(
- [
- mainTech ],
- {
- 'color': this._color
- },
- [
- { name: 'useTexture', value: true },
- { name: 'useModel', value: false },
- { name: 'alphaTest', value: false },
- { name: 'use2DPos', value: true },
- { name: 'useColor', value: true } ]
- );
-
- this._mainTech = mainTech;
- this._texture = null;
- }
-
- if ( Material$$1 ) SpriteMaterial.__proto__ = Material$$1;
- SpriteMaterial.prototype = Object.create( Material$$1 && Material$$1.prototype );
- SpriteMaterial.prototype.constructor = SpriteMaterial;
-
- var prototypeAccessors = { effect: { configurable: true },useTexture: { configurable: true },useModel: { configurable: true },use2DPos: { configurable: true },useColor: { configurable: true },texture: { configurable: true },color: { configurable: true } };
-
- prototypeAccessors.effect.get = function () {
- return this._effect;
- };
-
- prototypeAccessors.useTexture.get = function () {
- return this._effect.getDefine('useTexture');
- };
-
- prototypeAccessors.useTexture.set = function (val) {
- this._effect.define('useTexture', val);
- };
-
- prototypeAccessors.useModel.get = function () {
- return this._effect.getDefine('useModel');
- };
-
- prototypeAccessors.useModel.set = function (val) {
- this._effect.define('useModel', val);
- };
-
- prototypeAccessors.use2DPos.get = function () {
- return this._effect.getDefine('use2DPos');
- };
-
- prototypeAccessors.use2DPos.set = function (val) {
- this._effect.define('use2DPos', val);
- };
-
- prototypeAccessors.useColor.get = function () {
- return this._effect.getDefine('useColor');
- };
-
- prototypeAccessors.useColor.set = function (val) {
- this._effect.define('useColor', val);
- };
-
- prototypeAccessors.texture.get = function () {
- return this._texture;
- };
-
- prototypeAccessors.texture.set = function (val) {
- if (this._texture !== val) {
- this._texture = val;
- this._effect.setProperty('texture', val.getImpl());
- this._texIds['texture'] = val.getId();
- }
- };
-
- prototypeAccessors.color.get = function () {
- return this._color;
- };
-
- prototypeAccessors.color.set = function (val) {
- var color = this._color;
- color.r = val.r / 255;
- color.g = val.g / 255;
- color.b = val.b / 255;
- color.a = val.a / 255;
- this._effect.setProperty('color', color);
- };
-
- SpriteMaterial.prototype.clone = function clone () {
- var copy = new SpriteMaterial();
- copy.texture = this.texture;
- copy.useTexture = this.useTexture;
- copy.useModel = this.useModel;
- copy.use2DPos = this.use2DPos;
- copy.useColor = this.useColor;
- copy.updateHash();
- return copy;
- };
-
- Object.defineProperties( SpriteMaterial.prototype, prototypeAccessors );
-
- return SpriteMaterial;
-}(Material));
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var GraySpriteMaterial = (function (Material$$1) {
- function GraySpriteMaterial() {
- Material$$1.call(this, false);
-
- var pass = new renderer.Pass('gray_sprite');
- pass.setDepth(false, false);
- pass.setCullMode(gfx.CULL_NONE);
- pass.setBlend(
- gfx.BLEND_FUNC_ADD,
- gfx.BLEND_SRC_ALPHA, gfx.BLEND_ONE_MINUS_SRC_ALPHA,
- gfx.BLEND_FUNC_ADD,
- gfx.BLEND_SRC_ALPHA, gfx.BLEND_ONE_MINUS_SRC_ALPHA
- );
-
- var mainTech = new renderer.Technique(
- ['transparent'],
- [
- { name: 'texture', type: renderer.PARAM_TEXTURE_2D },
- { name: 'color', type: renderer.PARAM_COLOR4 } ],
- [
- pass
- ]
- );
-
- this._color = {r: 1, g: 1, b: 1, a: 1};
- this._effect = new renderer.Effect(
- [
- mainTech ],
- {
- 'color': this._color
- },
- []
- );
-
- this._mainTech = mainTech;
- this._texture = null;
- }
-
- if ( Material$$1 ) GraySpriteMaterial.__proto__ = Material$$1;
- GraySpriteMaterial.prototype = Object.create( Material$$1 && Material$$1.prototype );
- GraySpriteMaterial.prototype.constructor = GraySpriteMaterial;
-
- var prototypeAccessors = { effect: { configurable: true },texture: { configurable: true },color: { configurable: true } };
-
- prototypeAccessors.effect.get = function () {
- return this._effect;
- };
-
- prototypeAccessors.texture.get = function () {
- return this._texture;
- };
-
- prototypeAccessors.texture.set = function (val) {
- if (this._texture !== val) {
- this._texture = val;
- this._effect.setProperty('texture', val.getImpl());
- this._texIds['texture'] = val.getId();
- }
- };
-
- prototypeAccessors.color.get = function () {
- return this._color;
- };
-
- prototypeAccessors.color.set = function (val) {
- var color = this._color;
- color.r = val.r / 255;
- color.g = val.g / 255;
- color.b = val.b / 255;
- color.a = val.a / 255;
- this._effect.setProperty('color', color);
- };
-
- GraySpriteMaterial.prototype.clone = function clone () {
- var copy = new GraySpriteMaterial();
- copy.texture = this.texture;
- copy.color = this.color;
- copy.updateHash();
- return copy;
- };
-
- Object.defineProperties( GraySpriteMaterial.prototype, prototypeAccessors );
-
- return GraySpriteMaterial;
-}(Material));
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var StencilMaterial = (function (Material$$1) {
- function StencilMaterial() {
- Material$$1.call(this, false);
-
- this._pass = new renderer.Pass('sprite');
- this._pass.setDepth(false, false);
- this._pass.setCullMode(gfx.CULL_NONE);
- this._pass.setBlend(
- gfx.BLEND_FUNC_ADD,
- gfx.BLEND_SRC_ALPHA, gfx.BLEND_ONE_MINUS_SRC_ALPHA,
- gfx.BLEND_FUNC_ADD,
- gfx.BLEND_SRC_ALPHA, gfx.BLEND_ONE_MINUS_SRC_ALPHA
- );
-
- var mainTech = new renderer.Technique(
- ['transparent'],
- [
- { name: 'texture', type: renderer.PARAM_TEXTURE_2D },
- { name: 'alphaThreshold', type: renderer.PARAM_FLOAT },
- { name: 'color', type: renderer.PARAM_COLOR4 } ],
- [
- this._pass
- ]
- );
-
- this._effect = new renderer.Effect(
- [
- mainTech ],
- {
- 'color': {r: 1, g: 1, b: 1, a: 1}
- },
- [
- { name: 'useTexture', value: true },
- { name: 'useModel', value: false },
- { name: 'alphaTest', value: true },
- { name: 'use2DPos', value: true },
- { name: 'useColor', value: true } ]
- );
-
- this._mainTech = mainTech;
- this._texture = null;
- }
-
- if ( Material$$1 ) StencilMaterial.__proto__ = Material$$1;
- StencilMaterial.prototype = Object.create( Material$$1 && Material$$1.prototype );
- StencilMaterial.prototype.constructor = StencilMaterial;
-
- var prototypeAccessors = { effect: { configurable: true },useTexture: { configurable: true },useModel: { configurable: true },useColor: { configurable: true },texture: { configurable: true },alphaThreshold: { configurable: true } };
-
- prototypeAccessors.effect.get = function () {
- return this._effect;
- };
-
- prototypeAccessors.useTexture.get = function () {
- this._effect.getDefine('useTexture');
- };
-
- prototypeAccessors.useTexture.set = function (val) {
- this._effect.define('useTexture', val);
- };
-
- prototypeAccessors.useModel.get = function () {
- this._effect.getDefine('useModel');
- };
-
- prototypeAccessors.useModel.set = function (val) {
- this._effect.define('useModel', val);
- };
-
- prototypeAccessors.useColor.get = function () {
- this._effect.getDefine('useColor');
- };
-
- prototypeAccessors.useColor.set = function (val) {
- this._effect.define('useColor', val);
- };
-
- prototypeAccessors.texture.get = function () {
- return this._texture;
- };
-
- prototypeAccessors.texture.set = function (val) {
- if (this._texture !== val) {
- this._texture = val;
- this._effect.setProperty('texture', val.getImpl());
- this._texIds['texture'] = val.getId();
- }
- };
-
- prototypeAccessors.alphaThreshold.get = function () {
- return this._effect.getProperty('alphaThreshold');
- };
-
- prototypeAccessors.alphaThreshold.set = function (val) {
- this._effect.setProperty('alphaThreshold', val);
- };
-
- StencilMaterial.prototype.clone = function clone () {
- var copy = new StencilMaterial();
- copy.useTexture = this.useTexture;
- copy.useModel = this.useModel;
- copy.useColor = this.useColor;
- copy.texture = this.texture;
- copy.alphaThreshold = this.alphaThreshold;
- copy.updateHash();
- return copy;
- };
-
- Object.defineProperties( StencilMaterial.prototype, prototypeAccessors );
-
- return StencilMaterial;
-}(Material));
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var MeshMaterial = (function (Material$$1) {
- function MeshMaterial() {
- Material$$1.call(this, false);
-
- var pass = new renderer.Pass('mesh');
- pass.setDepth(false, false);
- pass.setCullMode(gfx.CULL_NONE);
- pass.setBlend(
- gfx.BLEND_FUNC_ADD,
- gfx.BLEND_SRC_ALPHA, gfx.BLEND_ONE_MINUS_SRC_ALPHA,
- gfx.BLEND_FUNC_ADD,
- gfx.BLEND_SRC_ALPHA, gfx.BLEND_ONE_MINUS_SRC_ALPHA
- );
-
- var mainTech = new renderer.Technique(
- ['transparent'],
- [
- { name: 'texture', type: renderer.PARAM_TEXTURE_2D },
- { name: 'color', type: renderer.PARAM_COLOR4 },
-
- { name: 'u_jointsTexture', type: renderer.PARAM_TEXTURE_2D },
- { name: 'u_jointsTextureSize', type: renderer.PARAM_FLOAT },
- { name: 'u_jointMatrices', type: renderer.PARAM_MAT4 } ],
- [
- pass
- ]
- );
-
- this._effect = new renderer.Effect(
- [
- mainTech ],
- {
- 'color': {r: 1, g: 1, b: 1, a: 1}
- },
- [
- { name: 'useTexture', value: true },
- { name: 'useModel', value: false },
- { name: 'useSkinning', value: false },
- { name: 'useJointsTexture', valu: true},
- { name: 'useAttributeColor', valu: false} ]
- );
-
- this._mainTech = mainTech;
- this._texture = null;
- this._jointsTexture = null;
- this._jointsTextureSize = 0;
- this._color = {r: 1, g: 1, b: 1, a: 1};
- this._jointMatrices = null;
- }
-
- if ( Material$$1 ) MeshMaterial.__proto__ = Material$$1;
- MeshMaterial.prototype = Object.create( Material$$1 && Material$$1.prototype );
- MeshMaterial.prototype.constructor = MeshMaterial;
-
- var prototypeAccessors = { effect: { configurable: true },useModel: { configurable: true },useTexture: { configurable: true },useSkinning: { configurable: true },useJointsTexture: { configurable: true },useAttributeColor: { configurable: true },texture: { configurable: true },jointMatrices: { configurable: true },jointsTexture: { configurable: true },jointsTextureSize: { configurable: true },color: { configurable: true } };
-
- prototypeAccessors.effect.get = function () {
- return this._effect;
- };
-
- prototypeAccessors.useModel.get = function () {
- return this._effect.getDefine('useModel');
- };
-
- prototypeAccessors.useModel.set = function (val) {
- this._effect.define('useModel', val);
- };
-
- prototypeAccessors.useTexture.get = function () {
- return this._effect.getDefine('useTexture');
- };
-
- prototypeAccessors.useTexture.set = function (val) {
- this._effect.define('useTexture', val);
- };
-
- prototypeAccessors.useSkinning.get = function () {
- return this._effect.getDefine('useSkinning');
- };
-
- prototypeAccessors.useSkinning.set = function (val) {
- this._effect.define('useSkinning', val);
- };
-
- prototypeAccessors.useJointsTexture.get = function () {
- return this._effect.getDefine('useJointsTexture');
- };
-
- prototypeAccessors.useJointsTexture.set = function (val) {
- this._effect.define('useJointsTexture', val);
- };
-
- prototypeAccessors.useAttributeColor.get = function () {
- return this._effect.getDefine('useAttributeColor');
- };
-
- prototypeAccessors.useAttributeColor.set = function (val) {
- this._effect.define('useAttributeColor', val);
- };
-
- prototypeAccessors.texture.get = function () {
- return this._texture;
- };
-
- prototypeAccessors.texture.set = function (val) {
- if (this._texture !== val) {
- this._texture = val;
- this._effect.setProperty('texture', val.getImpl());
- this._texIds['texture'] = val.getId();
- }
- };
-
- prototypeAccessors.jointMatrices.get = function () {
- return this._jointMatrices;
- };
-
- prototypeAccessors.jointMatrices.set = function (val) {
- this._jointMatrices = val;
- this._effect.setProperty('u_jointMatrices', val);
- };
-
- prototypeAccessors.jointsTexture.get = function () {
- return this._jointsTexture;
- };
-
- prototypeAccessors.jointsTexture.set = function (val) {
- if (this._jointsTexture !== val) {
- this._jointsTexture = val;
- this._effect.setProperty('u_jointsTexture', val.getImpl());
- this._texIds['jointsTexture'] = val.getId();
- }
- };
-
- prototypeAccessors.jointsTextureSize.get = function () {
- return this._jointsTextureSize;
- };
-
- prototypeAccessors.jointsTextureSize.set = function (val) {
- if (this._jointsTextureSize !== val) {
- this._jointsTextureSize = val;
- this._effect.setProperty('u_jointsTextureSize', val);
- }
- };
-
- prototypeAccessors.color.get = function () {
- return this._effect.getProperty('color');
- };
-
- prototypeAccessors.color.set = function (val) {
- var color = this._color;
- color.r = val.r / 255;
- color.g = val.g / 255;
- color.b = val.b / 255;
- color.a = val.a / 255;
- this._effect.setProperty('color', color);
- };
-
- MeshMaterial.prototype.clone = function clone () {
- var copy = new MeshMaterial();
- copy.texture = this.texture;
- copy.jointsTexture = this.jointsTexture;
- copy.jointsTextureSize = this.jointsTextureSize;
- copy.useTexture = this.useTexture;
- copy.color = this.color;
- copy.useModel = this.useModel;
- copy.useSkinning = this.useSkinning;
- copy.useJointsTexture = this.useJointsTexture;
- copy.useAttributeColor = this.useAttributeColor;
- copy.updateHash();
- return copy;
- };
-
- Object.defineProperties( MeshMaterial.prototype, prototypeAccessors );
-
- return MeshMaterial;
-}(Material));
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var Device$2 = function Device(canvasEL) {
- var ctx;
-
- try {
- ctx = canvasEL.getContext('2d');
- } catch (err) {
- console.error(err);
- return;
- }
-
- // statics
- this._canvas = canvasEL;
- this._ctx = ctx;
- this._caps = {}; // capability
- this._stats = {
- drawcalls: 0,
- };
-
- // runtime
- this._vx = this._vy = this._vw = this._vh = 0;
- this._sx = this._sy = this._sw = this._sh = 0;
-};
-
-Device$2.prototype._restoreTexture = function _restoreTexture (unit) {
-};
-
-// ===============================
-// Immediate Settings
-// ===============================
-
-/**
- * @method setViewport
- * @param {Number} x
- * @param {Number} y
- * @param {Number} w
- * @param {Number} h
- */
-Device$2.prototype.setViewport = function setViewport (x, y, w, h) {
- if (
- this._vx !== x ||
- this._vy !== y ||
- this._vw !== w ||
- this._vh !== h
- ) {
- this._vx = x;
- this._vy = y;
- this._vw = w;
- this._vh = h;
- }
-};
-
-/**
- * @method setScissor
- * @param {Number} x
- * @param {Number} y
- * @param {Number} w
- * @param {Number} h
- */
-Device$2.prototype.setScissor = function setScissor (x, y, w, h) {
- if (
- this._sx !== x ||
- this._sy !== y ||
- this._sw !== w ||
- this._sh !== h
- ) {
- this._sx = x;
- this._sy = y;
- this._sw = w;
- this._sh = h;
- }
-};
-
-Device$2.prototype.clear = function clear (color) {
- var ctx = this._ctx;
- ctx.clearRect(this._vx, this._vy, this._vw, this._vh);
- if (color && (color[0] !== 0 || color[1] !== 0 || color[2] !== 0)) {
- ctx.fillStyle = 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] +')';
- ctx.globalAlpha = color[3];
- ctx.fillRect(this._vx, this._vy, this._vw, this._vh);
- }
-};
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var Texture2D$2 = function Texture2D(device, options) {
- this._device = device;
-
- this._width = 4;
- this._height = 4;
-
- this._image = null;
-
- if (options) {
- if (options.width !== undefined) {
- this._width = options.width;
- }
- if (options.height !== undefined) {
- this._height = options.height;
- }
-
- this.updateImage(options);
- }
-};
-
-Texture2D$2.prototype.update = function update (options) {
- this.updateImage(options);
-};
-
-Texture2D$2.prototype.updateImage = function updateImage (options) {
- if (options.images && options.images[0]) {
- var image = options.images[0];
- if (image && image !== this._image) {
- this._image = image;
- }
- }
-};
-
-Texture2D$2.prototype.destroy = function destroy () {
- this._image = null;
-};
-
-var canvas = {
- Device: Device$2,
- Texture2D: Texture2D$2
-};
-
-// intenral
-// deps
-var Scene$2 = renderer.Scene;
-var Camera$2 = renderer.Camera;
-var View$2 = renderer.View;
-var Texture2D$4 = gfx.Texture2D;
-var Device$4 = gfx.Device;
-var Model$2 = renderer.Model;
-var InputAssembler$2 = renderer.InputAssembler;
-
-renderer.addStage('transparent');
-
-var renderEngine = {
- // core classes
- Device: Device$4,
- ForwardRenderer: ForwardRenderer,
- Texture2D: Texture2D$4,
-
- // Canvas render support
- canvas: canvas,
-
- // render scene
- Scene: Scene$2,
- Camera: Camera$2,
- View: View$2,
- Model: Model$2,
- RenderData: RenderData,
- IARenderData: IARenderData,
- InputAssembler: InputAssembler$2,
-
- // assets
- Asset: Asset,
- TextureAsset: Texture$2,
- Material: Material,
-
- // materials
- SpriteMaterial: SpriteMaterial,
- GraySpriteMaterial: GraySpriteMaterial,
- StencilMaterial: StencilMaterial,
- MeshMaterial: MeshMaterial,
-
- // shaders
- shaders: shaders,
-
- // memop
- RecyclePool: RecyclePool,
- Pool: Pool,
-
- // modules
- math: math,
- renderer: renderer,
- gfx: gfx,
-};
-
-module.exports = renderEngine;
diff --git a/cocos2d/core/renderer/render-engine.jsb.js b/cocos2d/core/renderer/render-engine.jsb.js
deleted file mode 100644
index 5fc7a5a1970..00000000000
--- a/cocos2d/core/renderer/render-engine.jsb.js
+++ /dev/null
@@ -1,10478 +0,0 @@
-
-/****************************************************************************
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- render-engine v1.2.0
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-
-'use strict';
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var gl = window.__gl;
-
-var _filterGL = [
- [ gl.GL_NEAREST, gl.GL_NEAREST_MIPMAP_NEAREST, gl.GL_NEAREST_MIPMAP_LINEAR ],
- [ gl.GL_LINEAR, gl.GL_LINEAR_MIPMAP_NEAREST, gl.GL_LINEAR_MIPMAP_LINEAR ] ];
-
-var _textureFmtGL = [
- // TEXTURE_FMT_RGB_DXT1: 0
- { format: gl.RGB, internalFormat: gl.COMPRESSED_RGB_S3TC_DXT1_EXT, pixelType: 0, bpp: 3 },
-
- // TEXTURE_FMT_RGBA_DXT1: 1
- { format: gl.RGBA, internalFormat: gl.COMPRESSED_RGBA_S3TC_DXT1_EXT, pixelType: 0, bpp: 4 },
-
- // TEXTURE_FMT_RGBA_DXT3: 2
- { format: gl.RGBA, internalFormat: gl.COMPRESSED_RGBA_S3TC_DXT3_EXT, pixelType: 0, bpp: 8 },
-
- // TEXTURE_FMT_RGBA_DXT5: 3
- { format: gl.RGBA, internalFormat: gl.COMPRESSED_RGBA_S3TC_DXT5_EXT, pixelType: 0, bpp: 8 },
-
- // TEXTURE_FMT_RGB_ETC1: 4
- { format: gl.RGB, internalFormat: gl.COMPRESSED_RGB_ETC1_WEBGL, pixelType: 0, bpp: 0 },
-
- // TEXTURE_FMT_RGB_PVRTC_2BPPV1: 5
- { format: gl.RGB, internalFormat: gl.COMPRESSED_RGB_PVRTC_2BPPV1_IMG, pixelType: 0, bpp: 0 },
-
- // TEXTURE_FMT_RGBA_PVRTC_2BPPV1: 6
- { format: gl.RGBA, internalFormat: gl.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, pixelType: 0, bpp:0 },
-
- // TEXTURE_FMT_RGB_PVRTC_4BPPV1: 7
- { format: gl.RGB, internalFormat: gl.COMPRESSED_RGB_PVRTC_4BPPV1_IMG, pixelType: 0, bpp: 0 },
-
- // TEXTURE_FMT_RGBA_PVRTC_4BPPV1: 8
- { format: gl.RGBA, internalFormat: gl.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, pixelType: null },
-
- // TEXTURE_FMT_A8: 9
- { format: gl.ALPHA, internalFormat: gl.ALPHA, pixelType: gl.UNSIGNED_BYTE, bpp: 8 },
-
- // TEXTURE_FMT_L8: 10
- { format: gl.LUMINANCE, internalFormat: gl.LUMINANCE, pixelType: gl.UNSIGNED_BYTE, bpp: 8 },
-
- // TEXTURE_FMT_L8_A8: 11
- { format: gl.LUMINANCE_ALPHA, internalFormat: gl.LUMINANCE_ALPHA, pixelType: gl.UNSIGNED_BYTE, bpp: 16 },
-
- // TEXTURE_FMT_R5_G6_B5: 12
- { format: gl.RGB, internalFormat: gl.RGB, pixelType: gl.UNSIGNED_SHORT_5_6_5, bpp: 16 },
-
- // TEXTURE_FMT_R5_G5_B5_A1: 13
- { format: gl.RGBA, internalFormat: gl.RGBA, pixelType: gl.UNSIGNED_SHORT_5_5_5_1, bpp: 16 },
-
- // TEXTURE_FMT_R4_G4_B4_A4: 14
- { format: gl.RGBA, internalFormat: gl.RGBA, pixelType: gl.UNSIGNED_SHORT_4_4_4_4, bpp: 16 },
-
- // TEXTURE_FMT_RGB8: 15
- { format: gl.RGB, internalFormat: gl.RGB, pixelType: gl.UNSIGNED_BYTE, bpp: 24 },
-
- // TEXTURE_FMT_RGBA8: 16
- { format: gl.RGBA, internalFormat: gl.RGBA, pixelType: gl.UNSIGNED_BYTE, bpp: 32 },
-
- // TEXTURE_FMT_RGB16F: 17
- { format: gl.RGB, internalFormat: gl.RGB, pixelType: gl.HALF_FLOAT_OES, bpp: 0 },
-
- // TEXTURE_FMT_RGBA16F: 18
- { format: gl.RGBA, internalFormat: gl.RGBA, pixelType: gl.HALF_FLOAT_OES, bpp: 0 },
-
- // TEXTURE_FMT_RGB32F: 19
- { format: gl.RGB, internalFormat: gl.RGB, pixelType: gl.FLOAT, bpp: 96 },
-
- // TEXTURE_FMT_RGBA32F: 20
- { format: gl.RGBA, internalFormat: gl.RGBA, pixelType: gl.FLOAT, bpp: 128 },
-
- // TEXTURE_FMT_R32F: 21
- { format: null, internalFormat: null, pixelType: 0, bpp: 0 },
-
- // TEXTURE_FMT_111110F: 22
- { format: null, internalFormat: null, pixelType: 0, bpp: 0 },
-
- // TEXTURE_FMT_SRGB: 23
- { format: null, internalFormat: null, pixelType: 0, bpp: 0 },
-
- // TEXTURE_FMT_SRGBA: 24
- { format: null, internalFormat: null, pixelType: 0, bpp: 0 },
-
- // TEXTURE_FMT_D16: 25
- // TODO: fix it on android
- { format: gl.DEPTH_COMPONENT, internalFormat: gl.DEPTH_COMPONENT16, pixelType: gl.UNSIGNED_SHORT },
-
- // TEXTURE_FMT_D24: 26
- // { format: gl.DEPTH_COMPONENT, internalFormat: gl.DEPTH_COMPONENT24, pixelType: gl.FLOAT },
-
- // TEXTURE_FMT_D24S8: 27
- { format: null, internalFormat: null, pixelType: 0, bpp: 0 } ];
-
-/**
- * enums
- */
-var enums = {
- // buffer usage
- USAGE_STATIC: 35044, // gl.STATIC_DRAW
- USAGE_DYNAMIC: 35048, // gl.DYNAMIC_DRAW
- USAGE_STREAM: 35040, // gl.STREAM_DRAW
-
- // index buffer format
- INDEX_FMT_UINT8: 5121, // gl.UNSIGNED_BYTE
- INDEX_FMT_UINT16: 5123, // gl.UNSIGNED_SHORT
- INDEX_FMT_UINT32: 5125, // gl.UNSIGNED_INT (OES_element_index_uint)
-
- // vertex attribute semantic
- ATTR_POSITION: 'a_position',
- ATTR_NORMAL: 'a_normal',
- ATTR_TANGENT: 'a_tangent',
- ATTR_BITANGENT: 'a_bitangent',
- ATTR_WEIGHTS: 'a_weights',
- ATTR_JOINTS: 'a_joints',
- ATTR_COLOR: 'a_color',
- ATTR_COLOR0: 'a_color0',
- ATTR_COLOR1: 'a_color1',
- ATTR_UV: 'a_uv',
- ATTR_UV0: 'a_uv0',
- ATTR_UV1: 'a_uv1',
- ATTR_UV2: 'a_uv2',
- ATTR_UV3: 'a_uv3',
- ATTR_UV4: 'a_uv4',
- ATTR_UV5: 'a_uv5',
- ATTR_UV6: 'a_uv6',
- ATTR_UV7: 'a_uv7',
-
- // vertex attribute type
- ATTR_TYPE_INT8: 5120, // gl.BYTE
- ATTR_TYPE_UINT8: 5121, // gl.UNSIGNED_BYTE
- ATTR_TYPE_INT16: 5122, // gl.SHORT
- ATTR_TYPE_UINT16: 5123, // gl.UNSIGNED_SHORT
- ATTR_TYPE_INT32: 5124, // gl.INT
- ATTR_TYPE_UINT32: 5125, // gl.UNSIGNED_INT
- ATTR_TYPE_FLOAT32: 5126, // gl.FLOAT
-
- // texture filter
- FILTER_NEAREST: 0,
- FILTER_LINEAR: 1,
-
- // texture wrap mode
- WRAP_REPEAT: 10497, // gl.REPEAT
- WRAP_CLAMP: 33071, // gl.CLAMP_TO_EDGE
- WRAP_MIRROR: 33648, // gl.MIRRORED_REPEAT
-
- // texture format
- // compress formats
- TEXTURE_FMT_RGB_DXT1: 0,
- TEXTURE_FMT_RGBA_DXT1: 1,
- TEXTURE_FMT_RGBA_DXT3: 2,
- TEXTURE_FMT_RGBA_DXT5: 3,
- TEXTURE_FMT_RGB_ETC1: 4,
- TEXTURE_FMT_RGB_PVRTC_2BPPV1: 5,
- TEXTURE_FMT_RGBA_PVRTC_2BPPV1: 6,
- TEXTURE_FMT_RGB_PVRTC_4BPPV1: 7,
- TEXTURE_FMT_RGBA_PVRTC_4BPPV1: 8,
-
- // normal formats
- TEXTURE_FMT_A8: 9,
- TEXTURE_FMT_L8: 10,
- TEXTURE_FMT_L8_A8: 11,
- TEXTURE_FMT_R5_G6_B5: 12,
- TEXTURE_FMT_R5_G5_B5_A1: 13,
- TEXTURE_FMT_R4_G4_B4_A4: 14,
- TEXTURE_FMT_RGB8: 15,
- TEXTURE_FMT_RGBA8: 16,
- TEXTURE_FMT_RGB16F: 17,
- TEXTURE_FMT_RGBA16F: 18,
- TEXTURE_FMT_RGB32F: 19,
- TEXTURE_FMT_RGBA32F: 20,
- TEXTURE_FMT_R32F: 21,
- TEXTURE_FMT_111110F: 22,
- TEXTURE_FMT_SRGB: 23,
- TEXTURE_FMT_SRGBA: 24,
-
- // depth formats
- TEXTURE_FMT_D16: 25,
- TEXTURE_FMT_D24: 26,
- TEXTURE_FMT_D24S8: 27,
-
- // depth and stencil function
- DS_FUNC_NEVER: 512, // gl.NEVER
- DS_FUNC_LESS: 513, // gl.LESS
- DS_FUNC_EQUAL: 514, // gl.EQUAL
- DS_FUNC_LEQUAL: 515, // gl.LEQUAL
- DS_FUNC_GREATER: 516, // gl.GREATER
- DS_FUNC_NOTEQUAL: 517, // gl.NOTEQUAL
- DS_FUNC_GEQUAL: 518, // gl.GEQUAL
- DS_FUNC_ALWAYS: 519, // gl.ALWAYS
-
- // render-buffer format
- RB_FMT_RGBA4: 32854, // gl.RGBA4
- RB_FMT_RGB5_A1: 32855, // gl.RGB5_A1
- RB_FMT_RGB565: 36194, // gl.RGB565
- RB_FMT_D16: 33189, // gl.DEPTH_COMPONENT16
- RB_FMT_S8: 36168, // gl.STENCIL_INDEX8
- RB_FMT_D24S8: 34041, // gl.DEPTH_STENCIL
-
- // blend-equation
- BLEND_FUNC_ADD: 32774, // gl.FUNC_ADD
- BLEND_FUNC_SUBTRACT: 32778, // gl.FUNC_SUBTRACT
- BLEND_FUNC_REVERSE_SUBTRACT: 32779, // gl.FUNC_REVERSE_SUBTRACT
-
- // blend
- BLEND_ZERO: 0, // gl.ZERO
- BLEND_ONE: 1, // gl.ONE
- BLEND_SRC_COLOR: 768, // gl.SRC_COLOR
- BLEND_ONE_MINUS_SRC_COLOR: 769, // gl.ONE_MINUS_SRC_COLOR
- BLEND_DST_COLOR: 774, // gl.DST_COLOR
- BLEND_ONE_MINUS_DST_COLOR: 775, // gl.ONE_MINUS_DST_COLOR
- BLEND_SRC_ALPHA: 770, // gl.SRC_ALPHA
- BLEND_ONE_MINUS_SRC_ALPHA: 771, // gl.ONE_MINUS_SRC_ALPHA
- BLEND_DST_ALPHA: 772, // gl.DST_ALPHA
- BLEND_ONE_MINUS_DST_ALPHA: 773, // gl.ONE_MINUS_DST_ALPHA
- BLEND_CONSTANT_COLOR: 32769, // gl.CONSTANT_COLOR
- BLEND_ONE_MINUS_CONSTANT_COLOR: 32770, // gl.ONE_MINUS_CONSTANT_COLOR
- BLEND_CONSTANT_ALPHA: 32771, // gl.CONSTANT_ALPHA
- BLEND_ONE_MINUS_CONSTANT_ALPHA: 32772, // gl.ONE_MINUS_CONSTANT_ALPHA
- BLEND_SRC_ALPHA_SATURATE: 776, // gl.SRC_ALPHA_SATURATE
-
- // stencil operation
- STENCIL_OP_KEEP: 7680, // gl.KEEP
- STENCIL_OP_ZERO: 0, // gl.ZERO
- STENCIL_OP_REPLACE: 7681, // gl.REPLACE
- STENCIL_OP_INCR: 7682, // gl.INCR
- STENCIL_OP_INCR_WRAP: 34055, // gl.INCR_WRAP
- STENCIL_OP_DECR: 7683, // gl.DECR
- STENCIL_OP_DECR_WRAP: 34056, // gl.DECR_WRAP
- STENCIL_OP_INVERT: 5386, // gl.INVERT
-
- // cull
- CULL_NONE: 0,
- CULL_FRONT: 1028,
- CULL_BACK: 1029,
- CULL_FRONT_AND_BACK: 1032,
-
- // primitive type
- PT_POINTS: 0, // gl.POINTS
- PT_LINES: 1, // gl.LINES
- PT_LINE_LOOP: 2, // gl.LINE_LOOP
- PT_LINE_STRIP: 3, // gl.LINE_STRIP
- PT_TRIANGLES: 4, // gl.TRIANGLES
- PT_TRIANGLE_STRIP: 5, // gl.TRIANGLE_STRIP
- PT_TRIANGLE_FAN: 6, // gl.TRIANGLE_FAN
-};
-
-/**
- * @method attrTypeBytes
- * @param {ATTR_TYPE_*} attrType
- */
-function attrTypeBytes(attrType) {
- if (attrType === enums.ATTR_TYPE_INT8) {
- return 1;
- } else if (attrType === enums.ATTR_TYPE_UINT8) {
- return 1;
- } else if (attrType === enums.ATTR_TYPE_INT16) {
- return 2;
- } else if (attrType === enums.ATTR_TYPE_UINT16) {
- return 2;
- } else if (attrType === enums.ATTR_TYPE_INT32) {
- return 4;
- } else if (attrType === enums.ATTR_TYPE_UINT32) {
- return 4;
- } else if (attrType === enums.ATTR_TYPE_FLOAT32) {
- return 4;
- }
-
- console.warn(("Unknown ATTR_TYPE: " + attrType));
- return 0;
-}
-
-/**
- * @method glTextureFmt
- * @param {TEXTURE_FMT_*} fmt
- */
-function glTextureFmt(fmt) {
- var result = _textureFmtGL[fmt];
- if (result === undefined) {
- console.warn(("Unknown TEXTURE_FMT: " + fmt));
- return _textureFmtGL[enums.TEXTURE_FMT_RGBA8];
- }
-
- return result;
-}
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var gfx = window.gfx;
-
-// ====================
-// exports
-// ====================
-
-var VertexFormat = function VertexFormat(infos) {
- var this$1 = this;
-
- this._attr2el = {};
- this._elements = [];
- this._bytes = 0;
-
- var offset = 0;
- for (var i = 0, len = infos.length; i < len; ++i) {
- var info = infos[i];
- var el = {
- name: info.name,
- offset: offset,
- stride: 0,
- stream: -1,
- type: info.type,
- num: info.num,
- normalize: (info.normalize === undefined) ? false : info.normalize,
- bytes: info.num * attrTypeBytes(info.type),
- };
- // log('info.num is:' + info.num + ' attrTypeBytes(info.type) is:' + attrTypeBytes(info.type));
-
- this$1._attr2el[el.name] = el;
- this$1._elements.push(el);
-
- this$1._bytes += el.bytes;
- offset += el.bytes;
- }
-
- for (var i$1 = 0, len$1 = this._elements.length; i$1 < len$1; ++i$1) {
- var el$1 = this$1._elements[i$1];
- el$1.stride = this$1._bytes;
- }
-
- this._nativeObj = new gfx.VertexFormatNative(this._elements);
-};
-
-/**
- * @method element
- * @param {string} attrName
- */
-VertexFormat.prototype.element = function element (attrName) {
- return this._attr2el[attrName];
-};
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var gl$1 = window.__gl;
-var gfx$1 = window.gfx;
-
-window.device = gfx$1.Device.getInstance();
-window.device._gl = window.__gl;
-
-//FIXME:
-window.device._stats = { vb: 0 };
-window.device._caps = {
- maxVextexTextures: 16,
- maxFragUniforms: 1024,
- maxTextureUints: 8,
- maxVertexAttributes: 16,
- maxDrawBuffers: 8,
- maxColorAttatchments: 8
-};
-
-device.setBlendColor32 = device.setBlendColor;
-
-var _p = gfx$1.Program.prototype;
-_p._ctor = function(device, options) {
- this.init(device, options.vert, options.frag);
-};
-
-_p = gfx$1.VertexBuffer.prototype;
-_p._ctor = function(device, format, usage, data, numVertices) {
- this.init(device, format._nativeObj, usage, data, numVertices);
- this._nativePtr = this.self();
-};
-cc.defineGetterSetter(_p, "count", _p.getCount);
-
-_p = gfx$1.IndexBuffer.prototype;
-_p._ctor = function(device, format, usage, data, numIndices) {
- this.init(device, format, usage, data, numIndices);
- this._nativePtr = this.self();
-};
-cc.defineGetterSetter(_p, "count", _p.getCount);
-
-gfx$1.VertexFormat = VertexFormat;
-Object.assign(gfx$1, enums);
-
-function convertImages(images) {
- if (images) {
- for (var i = 0, len = images.length; i < len; ++i) {
- var image = images[i];
- if (image !== null) {
- if (image instanceof window.HTMLCanvasElement) {
- if (image._data) {
- images[i] = image._data._data;
- }
- else {
- images[i] = null;
- }
- }
- else if (image instanceof window.HTMLImageElement) {
- images[i] = image._data;
- }
- }
- }
- }
-}
-
-function convertOptions(options) {
- if (options.images && options.images[0] instanceof HTMLImageElement) {
- var image = options.images[0];
- options.glInternalFormat = image._glInternalFormat;
- options.glFormat = image._glFormat;
- options.glType = image._glType;
- options.bpp = image._bpp;
- options.compressed = image._compressed;
- options.premultiplyAlpha = image._premultiplyAlpha;
- }
- else if (options.images && options.images[0] instanceof HTMLCanvasElement) {
- options.glInternalFormat = gl$1.RGBA;
- options.glFormat = gl$1.RGBA;
- options.glType = gl$1.UNSIGNED_BYTE;
- options.bpp = 32;
- options.compressed = false;
- }
- else {
- var gltf = glTextureFmt(options.format);
- options.glInternalFormat = gltf.internalFormat;
- options.glFormat = gltf.format;
- options.glType = gltf.pixelType;
- options.bpp = gltf.bpp;
- options.compressed = options.glFormat >= enums.TEXTURE_FMT_RGB_DXT1 &&
- options.gltf <= enums.TEXTURE_FMT_RGBA_PVRTC_4BPPV1;
- }
-
- convertImages(options.images);
-}
-
-_p = gfx$1.Texture2D.prototype;
-_p._ctor = function(device, options) {
- convertOptions(options);
- this.init(device, options);
-};
-_p.destroy = function() {
-};
-_p.update = function(options) {
- convertOptions(options);
- this.updateNative(options);
-};
-_p.updateSubImage = function(option) {
- var images = [option.image];
- convertImages(images);
- var data = new Uint32Array(8 +
- (images[0].length + 3) / 4);
-
- data[0] = option.x;
- data[1] = option.y;
- data[2] = option.width;
- data[3] = option.height;
- data[4] = option.level;
- data[5] = option.flipY;
- data[6] = false;
- data[7] = images[0].length;
- var imageData = new Uint8Array(data.buffer);
- imageData.set(images[0], 32);
-
- this.updateSubImageNative(data);
-};
-cc.defineGetterSetter(_p, "_width", _p.getWidth);
-cc.defineGetterSetter(_p, "_height", _p.getHeight);
-
-_p = gfx$1.FrameBuffer.prototype;
-_p._ctor = function(device, width, height, options) {
- this.init(device, width, height, options);
-};
-
-gfx$1.RB_FMT_D16 = 0x81A5; // GL_DEPTH_COMPONENT16 hack for JSB
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var gfx$3 = window.gfx;
-
-var InputAssembler = function InputAssembler(vb, ib, pt) {
- if ( pt === void 0 ) pt = gfx$3.PT_TRIANGLES;
-
- this._vertexBuffer = vb;
- this._indexBuffer = ib;
- this._primitiveType = pt;
- this._start = 0;
- this._count = -1;
-
- // TODO: instancing data
- // this._stream = 0;
-};
-
-InputAssembler.prototype.getPrimitiveCount = function getPrimitiveCount () {
- if (this._count !== -1) {
- return this._count;
- }
-
- if (this._indexBuffer) {
- return this._indexBuffer.count;
- }
-
- return this._vertexBuffer.count;
-};
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var renderer = window.renderer;
-var _stageOffset = 0;
-var _name2stageID = {};
-
-var config = {
- addStage: function (name) {
- // already added
- if (_name2stageID[name] !== undefined) {
- return;
- }
-
- var stageID = 1 << _stageOffset;
- _name2stageID[name] = stageID;
-
- _stageOffset += 1;
-
- renderer.addStage(name);
- },
-
- stageID: function (name) {
- var id = _name2stageID[name];
- if (id === undefined) {
- return -1;
- }
- return id;
- },
-
- stageIDs: function (nameList) {
- var key = 0;
- for (var i = 0; i < nameList.length; ++i) {
- var id = _name2stageID[nameList[i]];
- if (id !== undefined) {
- key |= id;
- }
- }
- return key;
- }
-};
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var renderer$1 = window.renderer;
-var _genID = 0;
-
-var Technique = function Technique(stages, parameters, passes, layer) {
- if ( layer === void 0 ) layer = 0;
-
- this._id = _genID++;
- this._stageIDs = config.stageIDs(stages);
- this.stageIDs = this._stageIDs;
- this._parameters = parameters; // {name, type, size, val}
- this._passes = passes;
- this.passes = this._passes;
- this._layer = layer;
- this._stages = stages;
- // TODO: this._version = 'webgl' or 'webgl2' // ????
-
- var passesNative = [];
- for (var i = 0, len = passes.length; i < len; ++i) {
- passesNative.push(passes[i]._native);
- }
- this._nativeObj = new renderer$1.TechniqueNative(stages, parameters, passesNative, layer);
-
-};
-
-Technique.prototype.setStages = function setStages (stages) {
- this._stageIDs = config.stageIDs(stages);
- this._stages = stages;
-
- this._nativeObj.setStages(stages);
-};
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var gfx$4 = window.gfx;
-var renderer$2 = window.renderer;
-
-var Pass = function Pass(name) {
- this._programName = name;
-
- // cullmode
- this._cullMode = gfx$4.CULL_BACK;
-
- // blending
- this._blend = false;
- this._blendEq = gfx$4.BLEND_FUNC_ADD;
- this._blendAlphaEq = gfx$4.BLEND_FUNC_ADD;
- this._blendSrc = gfx$4.BLEND_ONE;
- this._blendDst = gfx$4.BLEND_ZERO;
- this._blendSrcAlpha = gfx$4.BLEND_ONE;
- this._blendDstAlpha = gfx$4.BLEND_ZERO;
- this._blendColor = 0xffffffff;
-
- // depth
- this._depthTest = false;
- this._depthWrite = false;
- this._depthFunc = gfx$4.DS_FUNC_LESS, this._stencilTest = false;
- // front
- this._stencilFuncFront = gfx$4.DS_FUNC_ALWAYS;
- this._stencilRefFront = 0;
- this._stencilMaskFront = 0xff;
- this._stencilFailOpFront = gfx$4.STENCIL_OP_KEEP;
- this._stencilZFailOpFront = gfx$4.STENCIL_OP_KEEP;
- this._stencilZPassOpFront = gfx$4.STENCIL_OP_KEEP;
- this._stencilWriteMaskFront = 0xff;
- // back
- this._stencilFuncBack = gfx$4.DS_FUNC_ALWAYS;
- this._stencilRefBack = 0;
- this._stencilMaskBack = 0xff;
- this._stencilFailOpBack = gfx$4.STENCIL_OP_KEEP;
- this._stencilZFailOpBack = gfx$4.STENCIL_OP_KEEP;
- this._stencilZPassOpBack = gfx$4.STENCIL_OP_KEEP;
- this._stencilWriteMaskBack = 0xff;
-
- var binary = new Uint32Array(25);
- binary[0] = this._cullMode;
- binary[1] = this._blendEq;
- binary[2] = this._blendSrc;
- binary[3] = this._blendDst;
- binary[4] = this._blendAlphaEq;
- binary[5] = this._blendSrcAlpha;
- binary[6] = this._blendDstAlpha;
- binary[7] = this._blendColor;
- binary[8] = this._depthTest;
- binary[9] = this._depthWrite;
- binary[10] = this._depthFunc;
- binary[11] = this._stencilFuncFront;
- binary[12] = this._stencilRefFront;
- binary[13] = this._stencilMaskFront;
- binary[14] = this._stencilFailOpFront;
- binary[15] = this._stencilZFailOpFront;
- binary[16] = this._stencilZPassOpFront;
- binary[17] = this._stencilWriteMaskFront;
- binary[18] = this._stencilFuncBack;
- binary[19] = this._stencilRefBack;
- binary[20] = this._stencilMaskBack;
- binary[21] = this._stencilFailOpBack;
- binary[22] = this._stencilZFailOpBack;
- binary[23] = this._stencilZPassOpBack;
- binary[24] = this._stencilWriteMaskBack;
- this._native = new renderer$2.PassNative();
- this._native.init(this._programName, binary);
-};
-
-Pass.prototype.setCullMode = function setCullMode (cullMode) {
- this._cullMode = cullMode;
-
- this._native.setCullMode(cullMode);
-};
-
-Pass.prototype.disableStecilTest = function disableStecilTest () {
- this._stencilTest = false;
-
- this._native.disableStecilTest();
-};
-
-Pass.prototype.setBlend = function setBlend (
- blendEq,
- blendSrc,
- blendDst,
- blendAlphaEq,
- blendSrcAlpha,
- blendDstAlpha,
- blendColor
-) {
- if ( blendEq === void 0 ) blendEq = gfx$4.BLEND_FUNC_ADD;
- if ( blendSrc === void 0 ) blendSrc = gfx$4.BLEND_ONE;
- if ( blendDst === void 0 ) blendDst = gfx$4.BLEND_ZERO;
- if ( blendAlphaEq === void 0 ) blendAlphaEq = gfx$4.BLEND_FUNC_ADD;
- if ( blendSrcAlpha === void 0 ) blendSrcAlpha = gfx$4.BLEND_ONE;
- if ( blendDstAlpha === void 0 ) blendDstAlpha = gfx$4.BLEND_ZERO;
- if ( blendColor === void 0 ) blendColor = 0xffffffff;
-
- this._blend = true;
- this._blendEq = blendEq;
- this._blendSrc = blendSrc;
- this._blendDst = blendDst;
- this._blendAlphaEq = blendAlphaEq;
- this._blendSrcAlpha = blendSrcAlpha;
- this._blendDstAlpha = blendDstAlpha;
- this._blendColor = blendColor;
-
- this._native.setBlend(blendEq,
- blendSrc,
- blendDst,
- blendAlphaEq,
- blendSrcAlpha,
- blendDstAlpha,
- blendColor);
-};
-
-Pass.prototype.setDepth = function setDepth (
- depthTest,
- depthWrite,
- depthFunc
-) {
- if ( depthTest === void 0 ) depthTest = false;
- if ( depthWrite === void 0 ) depthWrite = false;
- if ( depthFunc === void 0 ) depthFunc = gfx$4.DS_FUNC_LESS;
-
- this._depthTest = depthTest;
- this._depthWrite = depthWrite;
- this._depthFunc = depthFunc;
-
- this._native.setDepth(depthTest, depthWrite, depthFunc);
-};
-
-Pass.prototype.setStencilFront = function setStencilFront (
- stencilFunc,
- stencilRef,
- stencilMask,
- stencilFailOp,
- stencilZFailOp,
- stencilZPassOp,
- stencilWriteMask
-) {
- if ( stencilFunc === void 0 ) stencilFunc = gfx$4.DS_FUNC_ALWAYS;
- if ( stencilRef === void 0 ) stencilRef = 0;
- if ( stencilMask === void 0 ) stencilMask = 0xff;
- if ( stencilFailOp === void 0 ) stencilFailOp = gfx$4.STENCIL_OP_KEEP;
- if ( stencilZFailOp === void 0 ) stencilZFailOp = gfx$4.STENCIL_OP_KEEP;
- if ( stencilZPassOp === void 0 ) stencilZPassOp = gfx$4.STENCIL_OP_KEEP;
- if ( stencilWriteMask === void 0 ) stencilWriteMask = 0xff;
-
- this._stencilTest = true;
- this._stencilFuncFront = stencilFunc;
- this._stencilRefFront = stencilRef;
- this._stencilMaskFront = stencilMask;
- this._stencilFailOpFront = stencilFailOp;
- this._stencilZFailOpFront = stencilZFailOp;
- this._stencilZPassOpFront = stencilZPassOp;
- this._stencilWriteMaskFront = stencilWriteMask;
-
- this._native.setStencilFront(stencilFunc,
- stencilRef,
- stencilMask,
- stencilFailOp,
- stencilZFailOp,
- stencilZPassOp,
- stencilWriteMask);
-};
-
-Pass.prototype.setStencilBack = function setStencilBack (
- stencilFunc,
- stencilRef,
- stencilMask,
- stencilFailOp,
- stencilZFailOp,
- stencilZPassOp,
- stencilWriteMask
-) {
- if ( stencilFunc === void 0 ) stencilFunc = gfx$4.DS_FUNC_ALWAYS;
- if ( stencilRef === void 0 ) stencilRef = 0;
- if ( stencilMask === void 0 ) stencilMask = 0xff;
- if ( stencilFailOp === void 0 ) stencilFailOp = gfx$4.STENCIL_OP_KEEP;
- if ( stencilZFailOp === void 0 ) stencilZFailOp = gfx$4.STENCIL_OP_KEEP;
- if ( stencilZPassOp === void 0 ) stencilZPassOp = gfx$4.STENCIL_OP_KEEP;
- if ( stencilWriteMask === void 0 ) stencilWriteMask = 0xff;
-
- this._stencilTest = true;
- this._stencilFuncBack = stencilFunc;
- this._stencilRefBack = stencilRef;
- this._stencilMaskBack = stencilMask;
- this._stencilFailOpBack = stencilFailOp;
- this._stencilZFailOpBack = stencilZFailOp;
- this._stencilZPassOpBack = stencilZPassOp;
- this._stencilWriteMaskBack = stencilWriteMask;
-
- this._native.setStencilBack(stencilFunc,
- stencilRef,
- stencilMask,
- stencilFailOp,
- stencilZFailOp,
- stencilZPassOp,
- stencilWriteMask);
-};
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var Model = function Model() {
- this._poolID = -1;
- this._node = null;
- this._inputAssemblers = [];
- this._effects = [];
- this._defines = [];
- this._dynamicIA = false;
- this._viewID = -1;
-
- // TODO: we calculate aabb based on vertices
- // this._aabb
-};
-
-var prototypeAccessors = { inputAssemblerCount: { configurable: true },dynamicIA: { configurable: true },drawItemCount: { configurable: true } };
-
-prototypeAccessors.inputAssemblerCount.get = function () {
- return this._inputAssemblers.length;
-};
-
-prototypeAccessors.dynamicIA.get = function () {
- return this._dynamicIA;
-};
-
-prototypeAccessors.drawItemCount.get = function () {
- return this._dynamicIA ? 1 : this._inputAssemblers.length;
-};
-
-Model.prototype.setNode = function setNode (node) {
- this._node = node;
-};
-
-Model.prototype.setDynamicIA = function setDynamicIA (enabled) {
- this._dynamicIA = enabled;
-};
-
-Model.prototype.addInputAssembler = function addInputAssembler (ia) {
- if (this._inputAssemblers.indexOf(ia) !== -1) {
- return;
- }
- this._inputAssemblers.push(ia);
-};
-
-Model.prototype.clearInputAssemblers = function clearInputAssemblers () {
- this._inputAssemblers.length = 0;
-};
-
-Model.prototype.addEffect = function addEffect (effect) {
- if (this._effects.indexOf(effect) !== -1) {
- return;
- }
- this._effects.push(effect);
-
- //
- // let defs = Object.create(null);
- // effect.extractDefines(defs);
- // this._defines.push(defs);
-};
-
-Model.prototype.clearEffects = function clearEffects () {
- this._effects.length = 0;
- this._defines.length = 0;
-};
-
-Model.prototype.extractDrawItem = function extractDrawItem (out, index) {
- if (this._dynamicIA) {
- out.model = this;
- out.node = this._node;
- out.ia = null;
- out.effect = this._effects[0];
- out.defines = out.effect.extractDefines(this._defines[0]);
-
- return;
- }
-
- if (index >= this._inputAssemblers.length ) {
- out.model = null;
- out.node = null;
- out.ia = null;
- out.effect = null;
- out.defines = null;
-
- return;
- }
-
- out.model = this;
- out.node = this._node;
- out.ia = this._inputAssemblers[index];
-
- var effect, defines;
- if (index < this._effects.length) {
- effect = this._effects[index];
- defines = this._defines[index];
- } else {
- effect = this._effects[this._effects.length-1];
- defines = this._defines[this._effects.length-1];
- }
- out.effect = effect;
- out.defines = effect.extractDefines(defines);
-};
-
-Object.defineProperties( Model.prototype, prototypeAccessors );
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var renderer$3 = window.renderer;
-
-// projection
-renderer$3.PROJ_PERSPECTIVE = 0;
-renderer$3.PROJ_ORTHO = 1;
-
-// lights
-renderer$3.LIGHT_DIRECTIONAL = 0;
-renderer$3.LIGHT_POINT = 1;
-renderer$3.LIGHT_SPOT = 2;
-
-// shadows
-renderer$3.SHADOW_NONE = 0;
-renderer$3.SHADOW_HARD = 1;
-renderer$3.SHADOW_SOFT = 2;
-
-// parameter type
-renderer$3.PARAM_INT = 0;
-renderer$3.PARAM_INT2 = 1;
-renderer$3.PARAM_INT3 = 2;
-renderer$3.PARAM_INT4 = 3;
-renderer$3.PARAM_FLOAT = 4;
-renderer$3.PARAM_FLOAT2 = 5;
-renderer$3.PARAM_FLOAT3 = 6;
-renderer$3.PARAM_FLOAT4 = 7;
-renderer$3.PARAM_COLOR3 = 8;
-renderer$3.PARAM_COLOR4 = 9;
-renderer$3.PARAM_MAT2 = 10;
-renderer$3.PARAM_MAT3 = 11;
-renderer$3.PARAM_MAT4 = 12;
-renderer$3.PARAM_TEXTURE_2D = 13;
-renderer$3.PARAM_TEXTURE_CUBE = 14;
-
-// clear flags
-renderer$3.CLEAR_COLOR = 1;
-renderer$3.CLEAR_DEPTH = 2;
-renderer$3.CLEAR_STENCIL = 4;
-renderer$3.InputAssembler = InputAssembler;
-renderer$3.config = config;
-renderer$3.Effect = Effect;
-renderer$3.Technique = Technique;
-renderer$3.Pass = Pass;
-renderer$3.Model = Model;
-
-var models = [];
-var sizeOfModel = 13;
-var lengthOfCachedModels = 500;
-// length + 500 modles(8 for each model)
-var modelsData = new Float64Array(1 + lengthOfCachedModels*sizeOfModel);
-var modelsData32 = new Float32Array(modelsData.buffer);
-var fillModelData = function() {
- if (models.length > lengthOfCachedModels) {
- modelsData = new Floa64Array(1 + models.length*sizeOfModel);
- lengthOfCachedModels = models.length;
- modelsData32 = new Float32Array(modelsData.buffer);
- }
-
- modelsData[0] = models.length;
- var index64 = 1;
- var index32 = 2;
- var model;
- var worldMatrix;
- var ia;
- for (var i = 0, len = models.length; i < len; ++i) {
- model = models[i];
-
- ia = model._inputAssemblers[0];
-
- // 3 elements of 64 bits data
- modelsData[index64++] = model._effects[0]._nativePtr;
- modelsData[index64++] = ia._vertexBuffer._nativePtr;
- modelsData[index64++] = ia._indexBuffer._nativePtr;
-
- index32 += 6;
- modelsData32[index32++] = model._dynamicIA;
- modelsData32[index32++] = model._viewID;
- worldMatrix = model._node.getWorldRTInAB();
- modelsData32.set(worldMatrix, index32);
- index32 += 16;
-
- modelsData32[index32++] = ia._start;
- modelsData32[index32++] = ia._count;
-
- index64 += 10;
- }
-};
-
-// ForwardRenderer adapter
-var _p$1 = renderer$3.ForwardRenderer.prototype;
-_p$1._ctor = function(device, builtin) {
- this.init(device, builtin.programTemplates, builtin.defaultTexture, window.innerWidth, window.innerHeight);
-};
-_p$1.render = function(scene) {
- fillModelData();
- this.renderNative(scene, modelsData);
-
- models.length = 0;
-};
-
-// Scene
-_p$1 = renderer$3.Scene.prototype;
-_p$1.addModel = function(model) {
- models.push(model);
-};
-_p$1.removeModel = function() {};
-
-var chunks = {
-};
-
-var templates = [
- {
- name: 'gray_sprite',
- vert: '\n \nuniform mat4 viewProj;\nattribute vec3 a_position;\nattribute mediump vec2 a_uv0;\nvarying mediump vec2 uv0;\nvoid main () {\n vec4 pos = viewProj * vec4(a_position, 1);\n gl_Position = pos;\n uv0 = a_uv0;\n}',
- frag: '\n \nuniform sampler2D texture;\nvarying mediump vec2 uv0;\nuniform lowp vec4 color;\nvoid main () {\n vec4 c = color * texture2D(texture, uv0);\n float gray = 0.2126*c.r + 0.7152*c.g + 0.0722*c.b;\n gl_FragColor = vec4(gray, gray, gray, c.a);\n}',
- defines: [
- ],
- },
- {
- name: 'sprite',
- vert: '\n \nuniform mat4 viewProj;\n#ifdef use2DPos\nattribute vec2 a_position;\n#else\nattribute vec3 a_position;\n#endif\nattribute lowp vec4 a_color;\n#ifdef useModel\n uniform mat4 model;\n#endif\n#ifdef useTexture\n attribute mediump vec2 a_uv0;\n varying mediump vec2 uv0;\n#endif\n#ifndef useColor\nvarying lowp vec4 v_fragmentColor;\n#endif\nvoid main () {\n mat4 mvp;\n #ifdef useModel\n mvp = viewProj * model;\n #else\n mvp = viewProj;\n #endif\n #ifdef use2DPos\n vec4 pos = mvp * vec4(a_position, 0, 1);\n #else\n vec4 pos = mvp * vec4(a_position, 1);\n #endif\n #ifndef useColor\n v_fragmentColor = a_color;\n #endif\n #ifdef useTexture\n uv0 = a_uv0;\n #endif\n gl_Position = pos;\n}',
- frag: '\n \n#ifdef useTexture\n uniform sampler2D texture;\n varying mediump vec2 uv0;\n#endif\n#ifdef alphaTest\n uniform lowp float alphaThreshold;\n#endif\n#ifdef useColor\n uniform lowp vec4 color;\n#else\n varying lowp vec4 v_fragmentColor;\n#endif\nvoid main () {\n #ifdef useColor\n vec4 o = color;\n #else\n vec4 o = v_fragmentColor;\n #endif\n #ifdef useTexture\n o *= texture2D(texture, uv0);\n #endif\n #ifdef alphaTest\n if (o.a <= alphaThreshold)\n discard;\n #endif\n gl_FragColor = o;\n}',
- defines: [
- { name: 'useTexture', },
- { name: 'useModel', },
- { name: 'alphaTest', },
- { name: 'use2DPos', },
- { name: 'useColor', } ],
- } ];
-
-var shaders = {
- chunks: chunks,
- templates: templates
-};
-
-// reference: https://github.com/mziccard/node-timsort
-
-/**
- * Default minimum size of a run.
- */
-var DEFAULT_MIN_MERGE = 32;
-
-/**
- * Minimum ordered subsequece required to do galloping.
- */
-var DEFAULT_MIN_GALLOPING = 7;
-
-/**
- * Default tmp storage length. Can increase depending on the size of the
- * smallest run to merge.
- */
-var DEFAULT_TMP_STORAGE_LENGTH = 256;
-
-/**
- * Pre-computed powers of 10 for efficient lexicographic comparison of
- * small integers.
- */
-var POWERS_OF_TEN = [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9];
-
-/**
- * Estimate the logarithm base 10 of a small integer.
- *
- * @param {number} x - The integer to estimate the logarithm of.
- * @return {number} - The estimated logarithm of the integer.
- */
-function log10(x) {
- if (x < 1e5) {
- if (x < 1e2) {
- return x < 1e1 ? 0 : 1;
- }
-
- if (x < 1e4) {
- return x < 1e3 ? 2 : 3;
- }
-
- return 4;
- }
-
- if (x < 1e7) {
- return x < 1e6 ? 5 : 6;
- }
-
- if (x < 1e9) {
- return x < 1e8 ? 7 : 8;
- }
-
- return 9;
-}
-
-/**
- * Default alphabetical comparison of items.
- *
- * @param {string|object|number} a - First element to compare.
- * @param {string|object|number} b - Second element to compare.
- * @return {number} - A positive number if a.toString() > b.toString(), a
- * negative number if .toString() < b.toString(), 0 otherwise.
- */
-function alphabeticalCompare(a, b) {
- if (a === b) {
- return 0;
- }
-
- if (~~a === a && ~~b === b) {
- if (a === 0 || b === 0) {
- return a < b ? -1 : 1;
- }
-
- if (a < 0 || b < 0) {
- if (b >= 0) {
- return -1;
- }
-
- if (a >= 0) {
- return 1;
- }
-
- a = -a;
- b = -b;
- }
-
- var al = log10(a);
- var bl = log10(b);
-
- var t = 0;
-
- if (al < bl) {
- a *= POWERS_OF_TEN[bl - al - 1];
- b /= 10;
- t = -1;
- } else if (al > bl) {
- b *= POWERS_OF_TEN[al - bl - 1];
- a /= 10;
- t = 1;
- }
-
- if (a === b) {
- return t;
- }
-
- return a < b ? -1 : 1;
- }
-
- var aStr = String(a);
- var bStr = String(b);
-
- if (aStr === bStr) {
- return 0;
- }
-
- return aStr < bStr ? -1 : 1;
-}
-
-/**
- * Compute minimum run length for TimSort
- *
- * @param {number} n - The size of the array to sort.
- */
-function minRunLength(n) {
- var r = 0;
-
- while (n >= DEFAULT_MIN_MERGE) {
- r |= (n & 1);
- n >>= 1;
- }
-
- return n + r;
-}
-
-/**
- * Counts the length of a monotonically ascending or strictly monotonically
- * descending sequence (run) starting at array[lo] in the range [lo, hi). If
- * the run is descending it is made ascending.
- *
- * @param {array} array - The array to reverse.
- * @param {number} lo - First element in the range (inclusive).
- * @param {number} hi - Last element in the range.
- * @param {function} compare - Item comparison function.
- * @return {number} - The length of the run.
- */
-function makeAscendingRun(array, lo, hi, compare) {
- var runHi = lo + 1;
-
- if (runHi === hi) {
- return 1;
- }
-
- // Descending
- if (compare(array[runHi++], array[lo]) < 0) {
- while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) {
- runHi++;
- }
-
- reverseRun(array, lo, runHi);
- // Ascending
- } else {
- while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) {
- runHi++;
- }
- }
-
- return runHi - lo;
-}
-
-/**
- * Reverse an array in the range [lo, hi).
- *
- * @param {array} array - The array to reverse.
- * @param {number} lo - First element in the range (inclusive).
- * @param {number} hi - Last element in the range.
- */
-function reverseRun(array, lo, hi) {
- hi--;
-
- while (lo < hi) {
- var t = array[lo];
- array[lo++] = array[hi];
- array[hi--] = t;
- }
-}
-
-/**
- * Perform the binary sort of the array in the range [lo, hi) where start is
- * the first element possibly out of order.
- *
- * @param {array} array - The array to sort.
- * @param {number} lo - First element in the range (inclusive).
- * @param {number} hi - Last element in the range.
- * @param {number} start - First element possibly out of order.
- * @param {function} compare - Item comparison function.
- */
-function binaryInsertionSort(array, lo, hi, start, compare) {
- if (start === lo) {
- start++;
- }
-
- for (; start < hi; start++) {
- var pivot = array[start];
-
- // Ranges of the array where pivot belongs
- var left = lo;
- var right = start;
-
- /*
- * pivot >= array[i] for i in [lo, left)
- * pivot < array[i] for i in in [right, start)
- */
- while (left < right) {
- var mid = (left + right) >>> 1;
-
- if (compare(pivot, array[mid]) < 0) {
- right = mid;
- } else {
- left = mid + 1;
- }
- }
-
- /*
- * Move elements right to make room for the pivot. If there are elements
- * equal to pivot, left points to the first slot after them: this is also
- * a reason for which TimSort is stable
- */
- var n = start - left;
- // Switch is just an optimization for small arrays
- switch (n) {
- case 3:
- array[left + 3] = array[left + 2];
- /* falls through */
- case 2:
- array[left + 2] = array[left + 1];
- /* falls through */
- case 1:
- array[left + 1] = array[left];
- break;
- default:
- while (n > 0) {
- array[left + n] = array[left + n - 1];
- n--;
- }
- }
-
- array[left] = pivot;
- }
-}
-
-/**
- * Find the position at which to insert a value in a sorted range. If the range
- * contains elements equal to the value the leftmost element index is returned
- * (for stability).
- *
- * @param {number} value - Value to insert.
- * @param {array} array - The array in which to insert value.
- * @param {number} start - First element in the range.
- * @param {number} length - Length of the range.
- * @param {number} hint - The index at which to begin the search.
- * @param {function} compare - Item comparison function.
- * @return {number} - The index where to insert value.
- */
-function gallopLeft(value, array, start, length, hint, compare) {
- var lastOffset = 0;
- var maxOffset = 0;
- var offset = 1;
-
- if (compare(value, array[start + hint]) > 0) {
- maxOffset = length - hint;
-
- while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) {
- lastOffset = offset;
- offset = (offset << 1) + 1;
-
- if (offset <= 0) {
- offset = maxOffset;
- }
- }
-
- if (offset > maxOffset) {
- offset = maxOffset;
- }
-
- // Make offsets relative to start
- lastOffset += hint;
- offset += hint;
-
- // value <= array[start + hint]
- } else {
- maxOffset = hint + 1;
- while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) {
- lastOffset = offset;
- offset = (offset << 1) + 1;
-
- if (offset <= 0) {
- offset = maxOffset;
- }
- }
- if (offset > maxOffset) {
- offset = maxOffset;
- }
-
- // Make offsets relative to start
- var tmp = lastOffset;
- lastOffset = hint - offset;
- offset = hint - tmp;
- }
-
- /*
- * Now array[start+lastOffset] < value <= array[start+offset], so value
- * belongs somewhere in the range (start + lastOffset, start + offset]. Do a
- * binary search, with invariant array[start + lastOffset - 1] < value <=
- * array[start + offset].
- */
- lastOffset++;
- while (lastOffset < offset) {
- var m = lastOffset + ((offset - lastOffset) >>> 1);
-
- if (compare(value, array[start + m]) > 0) {
- lastOffset = m + 1;
-
- } else {
- offset = m;
- }
- }
- return offset;
-}
-
-/**
- * Find the position at which to insert a value in a sorted range. If the range
- * contains elements equal to the value the rightmost element index is returned
- * (for stability).
- *
- * @param {number} value - Value to insert.
- * @param {array} array - The array in which to insert value.
- * @param {number} start - First element in the range.
- * @param {number} length - Length of the range.
- * @param {number} hint - The index at which to begin the search.
- * @param {function} compare - Item comparison function.
- * @return {number} - The index where to insert value.
- */
-function gallopRight(value, array, start, length, hint, compare) {
- var lastOffset = 0;
- var maxOffset = 0;
- var offset = 1;
-
- if (compare(value, array[start + hint]) < 0) {
- maxOffset = hint + 1;
-
- while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) {
- lastOffset = offset;
- offset = (offset << 1) + 1;
-
- if (offset <= 0) {
- offset = maxOffset;
- }
- }
-
- if (offset > maxOffset) {
- offset = maxOffset;
- }
-
- // Make offsets relative to start
- var tmp = lastOffset;
- lastOffset = hint - offset;
- offset = hint - tmp;
-
- // value >= array[start + hint]
- } else {
- maxOffset = length - hint;
-
- while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) {
- lastOffset = offset;
- offset = (offset << 1) + 1;
-
- if (offset <= 0) {
- offset = maxOffset;
- }
- }
-
- if (offset > maxOffset) {
- offset = maxOffset;
- }
-
- // Make offsets relative to start
- lastOffset += hint;
- offset += hint;
- }
-
- /*
- * Now array[start+lastOffset] < value <= array[start+offset], so value
- * belongs somewhere in the range (start + lastOffset, start + offset]. Do a
- * binary search, with invariant array[start + lastOffset - 1] < value <=
- * array[start + offset].
- */
- lastOffset++;
-
- while (lastOffset < offset) {
- var m = lastOffset + ((offset - lastOffset) >>> 1);
-
- if (compare(value, array[start + m]) < 0) {
- offset = m;
-
- } else {
- lastOffset = m + 1;
- }
- }
-
- return offset;
-}
-
-var TimSort = function TimSort(array, compare) {
- this.array = array;
- this.compare = compare;
- this.minGallop = DEFAULT_MIN_GALLOPING;
- this.length = array.length;
-
- this.tmpStorageLength = DEFAULT_TMP_STORAGE_LENGTH;
- if (this.length < 2 * DEFAULT_TMP_STORAGE_LENGTH) {
- this.tmpStorageLength = this.length >>> 1;
- }
-
- this.tmp = new Array(this.tmpStorageLength);
-
- this.stackLength =
- (this.length < 120 ? 5 :
- this.length < 1542 ? 10 :
- this.length < 119151 ? 19 : 40);
-
- this.runStart = new Array(this.stackLength);
- this.runLength = new Array(this.stackLength);
- this.stackSize = 0;
-};
-
-/**
- * Push a new run on TimSort's stack.
- *
- * @param {number} runStart - Start index of the run in the original array.
- * @param {number} runLength - Length of the run;
- */
-TimSort.prototype.pushRun = function pushRun (runStart, runLength) {
- this.runStart[this.stackSize] = runStart;
- this.runLength[this.stackSize] = runLength;
- this.stackSize += 1;
-};
-
-/**
- * Merge runs on TimSort's stack so that the following holds for all i:
- * 1) runLength[i - 3] > runLength[i - 2] + runLength[i - 1]
- * 2) runLength[i - 2] > runLength[i - 1]
- */
-TimSort.prototype.mergeRuns = function mergeRuns () {
- var this$1 = this;
-
- while (this.stackSize > 1) {
- var n = this$1.stackSize - 2;
-
- if ((n >= 1 &&
- this$1.runLength[n - 1] <= this$1.runLength[n] + this$1.runLength[n + 1]) ||
- (n >= 2 &&
- this$1.runLength[n - 2] <= this$1.runLength[n] + this$1.runLength[n - 1])) {
-
- if (this$1.runLength[n - 1] < this$1.runLength[n + 1]) {
- n--;
- }
-
- } else if (this$1.runLength[n] > this$1.runLength[n + 1]) {
- break;
- }
- this$1.mergeAt(n);
- }
-};
-
-/**
- * Merge all runs on TimSort's stack until only one remains.
- */
-TimSort.prototype.forceMergeRuns = function forceMergeRuns () {
- var this$1 = this;
-
- while (this.stackSize > 1) {
- var n = this$1.stackSize - 2;
-
- if (n > 0 && this$1.runLength[n - 1] < this$1.runLength[n + 1]) {
- n--;
- }
-
- this$1.mergeAt(n);
- }
-};
-
-/**
- * Merge the runs on the stack at positions i and i+1. Must be always be called
- * with i=stackSize-2 or i=stackSize-3 (that is, we merge on top of the stack).
- *
- * @param {number} i - Index of the run to merge in TimSort's stack.
- */
-TimSort.prototype.mergeAt = function mergeAt (i) {
- var compare = this.compare;
- var array = this.array;
-
- var start1 = this.runStart[i];
- var length1 = this.runLength[i];
- var start2 = this.runStart[i + 1];
- var length2 = this.runLength[i + 1];
-
- this.runLength[i] = length1 + length2;
-
- if (i === this.stackSize - 3) {
- this.runStart[i + 1] = this.runStart[i + 2];
- this.runLength[i + 1] = this.runLength[i + 2];
- }
-
- this.stackSize--;
-
- /*
- * Find where the first element in the second run goes in run1. Previous
- * elements in run1 are already in place
- */
- var k = gallopRight(array[start2], array, start1, length1, 0, compare);
- start1 += k;
- length1 -= k;
-
- if (length1 === 0) {
- return;
- }
-
- /*
- * Find where the last element in the first run goes in run2. Next elements
- * in run2 are already in place
- */
- length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare);
-
- if (length2 === 0) {
- return;
- }
-
- /*
- * Merge remaining runs. A tmp array with length = min(length1, length2) is
- * used
- */
- if (length1 <= length2) {
- this.mergeLow(start1, length1, start2, length2);
-
- } else {
- this.mergeHigh(start1, length1, start2, length2);
- }
-};
-
-/**
- * Merge two adjacent runs in a stable way. The runs must be such that the
- * first element of run1 is bigger than the first element in run2 and the
- * last element of run1 is greater than all the elements in run2.
- * The method should be called when run1.length <= run2.length as it uses
- * TimSort temporary array to store run1. Use mergeHigh if run1.length >
- * run2.length.
- *
- * @param {number} start1 - First element in run1.
- * @param {number} length1 - Length of run1.
- * @param {number} start2 - First element in run2.
- * @param {number} length2 - Length of run2.
- */
-TimSort.prototype.mergeLow = function mergeLow (start1, length1, start2, length2) {
-
- var compare = this.compare;
- var array = this.array;
- var tmp = this.tmp;
- var i = 0;
-
- for (i = 0; i < length1; i++) {
- tmp[i] = array[start1 + i];
- }
-
- var cursor1 = 0;
- var cursor2 = start2;
- var dest = start1;
-
- array[dest++] = array[cursor2++];
-
- if (--length2 === 0) {
- for (i = 0; i < length1; i++) {
- array[dest + i] = tmp[cursor1 + i];
- }
- return;
- }
-
- if (length1 === 1) {
- for (i = 0; i < length2; i++) {
- array[dest + i] = array[cursor2 + i];
- }
- array[dest + length2] = tmp[cursor1];
- return;
- }
-
- var minGallop = this.minGallop;
-
- while (true) {
- var count1 = 0;
- var count2 = 0;
- var exit = false;
-
- do {
- if (compare(array[cursor2], tmp[cursor1]) < 0) {
- array[dest++] = array[cursor2++];
- count2++;
- count1 = 0;
-
- if (--length2 === 0) {
- exit = true;
- break;
- }
-
- } else {
- array[dest++] = tmp[cursor1++];
- count1++;
- count2 = 0;
- if (--length1 === 1) {
- exit = true;
- break;
- }
- }
- } while ((count1 | count2) < minGallop);
-
- if (exit) {
- break;
- }
-
- do {
- count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare);
-
- if (count1 !== 0) {
- for (i = 0; i < count1; i++) {
- array[dest + i] = tmp[cursor1 + i];
- }
-
- dest += count1;
- cursor1 += count1;
- length1 -= count1;
- if (length1 <= 1) {
- exit = true;
- break;
- }
- }
-
- array[dest++] = array[cursor2++];
-
- if (--length2 === 0) {
- exit = true;
- break;
- }
-
- count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare);
-
- if (count2 !== 0) {
- for (i = 0; i < count2; i++) {
- array[dest + i] = array[cursor2 + i];
- }
-
- dest += count2;
- cursor2 += count2;
- length2 -= count2;
-
- if (length2 === 0) {
- exit = true;
- break;
- }
- }
- array[dest++] = tmp[cursor1++];
-
- if (--length1 === 1) {
- exit = true;
- break;
- }
-
- minGallop--;
-
- } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
-
- if (exit) {
- break;
- }
-
- if (minGallop < 0) {
- minGallop = 0;
- }
-
- minGallop += 2;
- }
-
- this.minGallop = minGallop;
-
- if (minGallop < 1) {
- this.minGallop = 1;
- }
-
- if (length1 === 1) {
- for (i = 0; i < length2; i++) {
- array[dest + i] = array[cursor2 + i];
- }
- array[dest + length2] = tmp[cursor1];
-
- } else if (length1 === 0) {
- throw new Error('mergeLow preconditions were not respected');
-
- } else {
- for (i = 0; i < length1; i++) {
- array[dest + i] = tmp[cursor1 + i];
- }
- }
-};
-
-/**
- * Merge two adjacent runs in a stable way. The runs must be such that the
- * first element of run1 is bigger than the first element in run2 and the
- * last element of run1 is greater than all the elements in run2.
- * The method should be called when run1.length > run2.length as it uses
- * TimSort temporary array to store run2. Use mergeLow if run1.length <=
- * run2.length.
- *
- * @param {number} start1 - First element in run1.
- * @param {number} length1 - Length of run1.
- * @param {number} start2 - First element in run2.
- * @param {number} length2 - Length of run2.
- */
-TimSort.prototype.mergeHigh = function mergeHigh (start1, length1, start2, length2) {
- var compare = this.compare;
- var array = this.array;
- var tmp = this.tmp;
- var i = 0;
-
- for (i = 0; i < length2; i++) {
- tmp[i] = array[start2 + i];
- }
-
- var cursor1 = start1 + length1 - 1;
- var cursor2 = length2 - 1;
- var dest = start2 + length2 - 1;
- var customCursor = 0;
- var customDest = 0;
-
- array[dest--] = array[cursor1--];
-
- if (--length1 === 0) {
- customCursor = dest - (length2 - 1);
-
- for (i = 0; i < length2; i++) {
- array[customCursor + i] = tmp[i];
- }
-
- return;
- }
-
- if (length2 === 1) {
- dest -= length1;
- cursor1 -= length1;
- customDest = dest + 1;
- customCursor = cursor1 + 1;
-
- for (i = length1 - 1; i >= 0; i--) {
- array[customDest + i] = array[customCursor + i];
- }
-
- array[dest] = tmp[cursor2];
- return;
- }
-
- var minGallop = this.minGallop;
-
- while (true) {
- var count1 = 0;
- var count2 = 0;
- var exit = false;
-
- do {
- if (compare(tmp[cursor2], array[cursor1]) < 0) {
- array[dest--] = array[cursor1--];
- count1++;
- count2 = 0;
- if (--length1 === 0) {
- exit = true;
- break;
- }
-
- } else {
- array[dest--] = tmp[cursor2--];
- count2++;
- count1 = 0;
- if (--length2 === 1) {
- exit = true;
- break;
- }
- }
-
- } while ((count1 | count2) < minGallop);
-
- if (exit) {
- break;
- }
-
- do {
- count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare);
-
- if (count1 !== 0) {
- dest -= count1;
- cursor1 -= count1;
- length1 -= count1;
- customDest = dest + 1;
- customCursor = cursor1 + 1;
-
- for (i = count1 - 1; i >= 0; i--) {
- array[customDest + i] = array[customCursor + i];
- }
-
- if (length1 === 0) {
- exit = true;
- break;
- }
- }
-
- array[dest--] = tmp[cursor2--];
-
- if (--length2 === 1) {
- exit = true;
- break;
- }
-
- count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare);
-
- if (count2 !== 0) {
- dest -= count2;
- cursor2 -= count2;
- length2 -= count2;
- customDest = dest + 1;
- customCursor = cursor2 + 1;
-
- for (i = 0; i < count2; i++) {
- array[customDest + i] = tmp[customCursor + i];
- }
-
- if (length2 <= 1) {
- exit = true;
- break;
- }
- }
-
- array[dest--] = array[cursor1--];
-
- if (--length1 === 0) {
- exit = true;
- break;
- }
-
- minGallop--;
-
- } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
-
- if (exit) {
- break;
- }
-
- if (minGallop < 0) {
- minGallop = 0;
- }
-
- minGallop += 2;
- }
-
- this.minGallop = minGallop;
-
- if (minGallop < 1) {
- this.minGallop = 1;
- }
-
- if (length2 === 1) {
- dest -= length1;
- cursor1 -= length1;
- customDest = dest + 1;
- customCursor = cursor1 + 1;
-
- for (i = length1 - 1; i >= 0; i--) {
- array[customDest + i] = array[customCursor + i];
- }
-
- array[dest] = tmp[cursor2];
-
- } else if (length2 === 0) {
- throw new Error('mergeHigh preconditions were not respected');
-
- } else {
- customCursor = dest - (length2 - 1);
- for (i = 0; i < length2; i++) {
- array[customCursor + i] = tmp[i];
- }
- }
-};
-
-/**
- * Sort an array in the range [lo, hi) using TimSort.
- *
- * @param {array} array - The array to sort.
- * @param {number} lo - First element in the range (inclusive).
- * @param {number} hi - Last element in the range.
- * @param {function=} compare - Item comparison function. Default is alphabetical.
- */
-function sort (array, lo, hi, compare) {
- if (!Array.isArray(array)) {
- throw new TypeError('Can only sort arrays');
- }
-
- /*
- * Handle the case where a comparison function is not provided. We do
- * lexicographic sorting
- */
-
- if (lo === undefined) {
- lo = 0;
- }
-
- if (hi === undefined) {
- hi = array.length;
- }
-
- if (compare === undefined) {
- compare = alphabeticalCompare;
- }
-
- var remaining = hi - lo;
-
- // The array is already sorted
- if (remaining < 2) {
- return;
- }
-
- var runLength = 0;
- // On small arrays binary sort can be used directly
- if (remaining < DEFAULT_MIN_MERGE) {
- runLength = makeAscendingRun(array, lo, hi, compare);
- binaryInsertionSort(array, lo, hi, lo + runLength, compare);
- return;
- }
-
- var ts = new TimSort(array, compare);
-
- var minRun = minRunLength(remaining);
-
- do {
- runLength = makeAscendingRun(array, lo, hi, compare);
- if (runLength < minRun) {
- var force = remaining;
- if (force > minRun) {
- force = minRun;
- }
-
- binaryInsertionSort(array, lo, lo + force, lo + runLength, compare);
- runLength = force;
- }
- // Push new run and merge if necessary
- ts.pushRun(lo, runLength);
- ts.mergeRuns();
-
- // Go find next run
- remaining -= runLength;
- lo += runLength;
-
- } while (remaining !== 0);
-
- // Force merging of remaining runs
- ts.forceMergeRuns();
-}
-
-var FixedArray = function FixedArray(size) {
- this._count = 0;
- this._data = new Array(size);
-};
-
-var prototypeAccessors$1 = { length: { configurable: true },data: { configurable: true } };
-
-FixedArray.prototype._resize = function _resize (size) {
- var this$1 = this;
-
- if (size > this._data.length) {
- for (var i = this._data.length; i < size; ++i) {
- this$1._data[i] = undefined;
- }
- }
-};
-
-prototypeAccessors$1.length.get = function () {
- return this._count;
-};
-
-prototypeAccessors$1.data.get = function () {
- return this._data;
-};
-
-FixedArray.prototype.reset = function reset () {
- var this$1 = this;
-
- for (var i = 0; i < this._count; ++i) {
- this$1._data[i] = undefined;
- }
-
- this._count = 0;
-};
-
-FixedArray.prototype.push = function push (val) {
- if (this._count >= this._data.length) {
- this._resize(this._data.length * 2);
- }
-
- this._data[this._count] = val;
- ++this._count;
-};
-
-FixedArray.prototype.pop = function pop () {
- --this._count;
-
- if (this._count < 0) {
- this._count = 0;
- }
-
- var ret = this._data[this._count];
- this._data[this._count] = undefined;
-
- return ret;
-};
-
-FixedArray.prototype.fastRemove = function fastRemove (idx) {
- if (idx >= this._count) {
- return;
- }
-
- var last = this._count - 1;
- this._data[idx] = this._data[last];
- this._data[last] = undefined;
- this._count -= 1;
-};
-
-FixedArray.prototype.indexOf = function indexOf (val) {
- var idx = this._data.indexOf(val);
- if (idx >= this._count) {
- return -1;
- }
-
- return idx;
-};
-
-FixedArray.prototype.sort = function sort$1 (cmp) {
- return sort(this._data, 0, this._count, cmp);
-};
-
-Object.defineProperties( FixedArray.prototype, prototypeAccessors$1 );
-
-var Pool = function Pool(fn, size) {
- var this$1 = this;
-
- this._fn = fn;
- this._idx = size - 1;
- this._frees = new Array(size);
-
- for (var i = 0; i < size; ++i) {
- this$1._frees[i] = fn();
- }
-};
-
-Pool.prototype._expand = function _expand (size) {
- var this$1 = this;
-
- var old = this._frees;
- this._frees = new Array(size);
-
- var len = size - old.length;
- for (var i = 0; i < len; ++i) {
- this$1._frees[i] = this$1._fn();
- }
-
- for (var i$1 = len, j = 0; i$1 < size; ++i$1, ++j) {
- this$1._frees[i$1] = old[j];
- }
-
- this._idx += len;
-};
-
-Pool.prototype.alloc = function alloc () {
- // create some more space (expand by 20%, minimum 1)
- if (this._idx < 0) {
- this._expand(Math.round(this._frees.length * 1.2) + 1);
- }
-
- var ret = this._frees[this._idx];
- this._frees[this._idx] = null;
- --this._idx;
-
- return ret;
-};
-
-Pool.prototype.free = function free (obj) {
- ++this._idx;
- this._frees[this._idx] = obj;
-};
-
-// NOTE: you must have `_prev` and `_next` field in the object returns by `fn`
-
-var LinkedArray = function LinkedArray(fn, size) {
- this._fn = fn;
- this._count = 0;
- this._head = null;
- this._tail = null;
-
- this._pool = new Pool(fn, size);
-};
-
-var prototypeAccessors$2 = { head: { configurable: true },tail: { configurable: true },length: { configurable: true } };
-
-prototypeAccessors$2.head.get = function () {
- return this._head;
-};
-
-prototypeAccessors$2.tail.get = function () {
- return this._tail;
-};
-
-prototypeAccessors$2.length.get = function () {
- return this._count;
-};
-
-LinkedArray.prototype.add = function add () {
- var node = this._pool.alloc();
-
- if (!this._tail) {
- this._head = node;
- } else {
- this._tail._next = node;
- node._prev = this._tail;
- }
- this._tail = node;
- this._count += 1;
-
- return node;
-};
-
-LinkedArray.prototype.remove = function remove (node) {
- if (node._prev) {
- node._prev._next = node._next;
- } else {
- this._head = node._next;
- }
-
- if (node._next) {
- node._next._prev = node._prev;
- } else {
- this._tail = node._prev;
- }
-
- node._next = null;
- node._prev = null;
- this._pool.free(node);
- this._count -= 1;
-};
-
-LinkedArray.prototype.forEach = function forEach (fn, binder) {
- var this$1 = this;
-
- var cursor = this._head;
- if (!cursor) {
- return;
- }
-
- if (binder) {
- fn = fn.bind(binder);
- }
-
- var idx = 0;
- var next = cursor;
-
- while (cursor) {
- next = cursor._next;
- fn(cursor, idx, this$1);
-
- cursor = next;
- ++idx;
- }
-};
-
-Object.defineProperties( LinkedArray.prototype, prototypeAccessors$2 );
-
-var RecyclePool = function RecyclePool(fn, size) {
- var this$1 = this;
-
- this._fn = fn;
- this._count = 0;
- this._data = new Array(size);
-
- for (var i = 0; i < size; ++i) {
- this$1._data[i] = fn();
- }
-};
-
-var prototypeAccessors$3 = { length: { configurable: true },data: { configurable: true } };
-
-prototypeAccessors$3.length.get = function () {
- return this._count;
-};
-
-prototypeAccessors$3.data.get = function () {
- return this._data;
-};
-
-RecyclePool.prototype.reset = function reset () {
- this._count = 0;
-};
-
-RecyclePool.prototype.resize = function resize (size) {
- var this$1 = this;
-
- if (size > this._data.length) {
- for (var i = this._data.length; i < size; ++i) {
- this$1._data[i] = this$1._fn();
- }
- }
-};
-
-RecyclePool.prototype.add = function add () {
- if (this._count >= this._data.length) {
- this.resize(this._data.length * 2);
- }
-
- return this._data[this._count++];
-};
-
-RecyclePool.prototype.remove = function remove (idx) {
- if (idx >= this._count) {
- return;
- }
-
- var last = this._count - 1;
- var tmp = this._data[idx];
- this._data[idx] = this._data[last];
- this._data[last] = tmp;
- this._count -= 1;
-};
-
-RecyclePool.prototype.sort = function sort$1 (cmp) {
- return sort(this._data, 0, this._count, cmp);
-};
-
-Object.defineProperties( RecyclePool.prototype, prototypeAccessors$3 );
-
-var _bufferPools = Array(8);
-for (var i = 0; i < 8; ++i) {
- _bufferPools[i] = [];
-}
-
-// Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
-
-/**
- * BaseRenderData is a core data abstraction for renderer, this is a abstract class.
- * An inherited render data type should define raw vertex datas.
- * User should also define the effect, vertex count and index count.
- */
-var BaseRenderData = function BaseRenderData () {
- this.material = null;
- this.vertexCount = 0;
- this.indiceCount = 0;
-};
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var _pool;
-var _dataPool = new Pool(function () {
- return {
- x: 0.0,
- y: 0.0,
- u: 0.0,
- v: 0.0,
- color: 0
- };
-}, 128);
-
-/**
- * RenderData is most widely used render data type.
- * It describes raw vertex data with a fixed data layout.
- * Each vertex is described by five property: x, y, u, v, color. The data layout might be extended in the future.
- * Vertex data objects are managed automatically by RenderData, user only need to set the dataLength property.
- * User can also define rendering index orders for the vertex list.
- */
-var RenderData = (function (BaseRenderData$$1) {
- function RenderData () {
- BaseRenderData$$1.call(this);
- this._data = [];
- this._indices = [];
-
- this._pivotX = 0;
- this._pivotY = 0;
- this._width = 0;
- this._height = 0;
-
- this.uvDirty = true;
- this.vertDirty = true;
- }
-
- if ( BaseRenderData$$1 ) RenderData.__proto__ = BaseRenderData$$1;
- RenderData.prototype = Object.create( BaseRenderData$$1 && BaseRenderData$$1.prototype );
- RenderData.prototype.constructor = RenderData;
-
- var prototypeAccessors = { type: { configurable: true },dataLength: { configurable: true } };
-
- prototypeAccessors.type.get = function () {
- return RenderData.type;
- };
-
- prototypeAccessors.dataLength.get = function () {
- return this._data.length;
- };
-
- prototypeAccessors.dataLength.set = function (length) {
- var data = this._data;
- if (data.length !== length) {
- // Free extra data
- for (var i = length; i < data.length; i++) {
- _dataPool.free(data[i]);
- }
- // Alloc needed data
- for (var i$1 = data.length; i$1 < length; i$1++) {
- data[i$1] = _dataPool.alloc();
- }
- data.length = length;
- }
- };
-
- RenderData.prototype.updateSizeNPivot = function updateSizeNPivot (width, height, pivotX, pivotY) {
- if (width !== this._width ||
- height !== this._height ||
- pivotX !== this._pivotX ||
- pivotY !== this._pivotY)
- {
- this._width = width;
- this._height = height;
- this._pivotX = pivotX;
- this._pivotY = pivotY;
- this.vertDirty = true;
- }
- };
-
- RenderData.alloc = function alloc () {
- return _pool.alloc();
- };
-
- RenderData.free = function free (data) {
- if (data instanceof RenderData) {
- for (var i = data.length-1; i > 0; i--) {
- _dataPool.free(data._data[i]);
- }
- data._data.length = 0;
- data._indices.length = 0;
- data.material = null;
- data.uvDirty = true;
- data.vertDirty = true;
- data.vertexCount = 0;
- data.indiceCount = 0;
- _pool.free(data);
- }
- };
-
- Object.defineProperties( RenderData.prototype, prototypeAccessors );
-
- return RenderData;
-}(BaseRenderData));
-
-RenderData.type = 'RenderData';
-
-_pool = new Pool(function () {
- return new RenderData();
-}, 32);
-
-// Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
-
-/**
- * IARenderData is user customized render data type, user should provide the entier input assembler.
- * IARenderData just defines a property `ia` for accessing the input assembler.
- * It doesn't manage memory so users should manage the memory of input assembler by themselves.
- */
-var IARenderData = (function (BaseRenderData$$1) {
- function IARenderData () {
- BaseRenderData$$1.call(this);
- this.ia = null;
- }
-
- if ( BaseRenderData$$1 ) IARenderData.__proto__ = BaseRenderData$$1;
- IARenderData.prototype = Object.create( BaseRenderData$$1 && BaseRenderData$$1.prototype );
- IARenderData.prototype.constructor = IARenderData;
-
- var prototypeAccessors = { type: { configurable: true } };
-
- prototypeAccessors.type.get = function () {
- return IARenderData.type;
- };
-
- Object.defineProperties( IARenderData.prototype, prototypeAccessors );
-
- return IARenderData;
-}(BaseRenderData));
-
-IARenderData.type = 'IARenderData';
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var Asset = function Asset(persist) {
- if ( persist === void 0 ) persist = true;
-
- this._loaded = false;
- this._persist = persist;
-};
-
-Asset.prototype.unload = function unload () {
- this._loaded = false;
-};
-
-Asset.prototype.reload = function reload () {
- // TODO
-};
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var Texture = (function (Asset$$1) {
- function Texture(persist) {
- if ( persist === void 0 ) persist = true;
-
- Asset$$1.call(this, persist);
-
- this._texture = null;
- }
-
- if ( Asset$$1 ) Texture.__proto__ = Asset$$1;
- Texture.prototype = Object.create( Asset$$1 && Asset$$1.prototype );
- Texture.prototype.constructor = Texture;
-
- Texture.prototype.getImpl = function getImpl () {
- return this._texture;
- };
-
- Texture.prototype.getId = function getId () {};
-
- Texture.prototype.destroy = function destroy () {
- this._texture && this._texture.destroy();
- };
-
- return Texture;
-}(Asset));
-
-/**
- * JS Implementation of MurmurHash2
- *
- * @author Gary Court
- * @see http://github.com/garycourt/murmurhash-js
- * @author Austin Appleby
- * @see http://sites.google.com/site/murmurhash/
- *
- * @param {string} str ASCII only
- * @param {number} seed Positive integer only
- * @return {number} 32-bit positive integer hash
- */
-
-function murmurhash2_32_gc(str, seed) {
- var
- l = str.length,
- h = seed ^ l,
- i = 0,
- k;
-
- while (l >= 4) {
- k =
- ((str.charCodeAt(i) & 0xff)) |
- ((str.charCodeAt(++i) & 0xff) << 8) |
- ((str.charCodeAt(++i) & 0xff) << 16) |
- ((str.charCodeAt(++i) & 0xff) << 24);
-
- k = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16));
- k ^= k >>> 24;
- k = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16));
-
- h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16)) ^ k;
-
- l -= 4;
- ++i;
- }
-
- switch (l) {
- case 3: h ^= (str.charCodeAt(i + 2) & 0xff) << 16;
- case 2: h ^= (str.charCodeAt(i + 1) & 0xff) << 8;
- case 1: h ^= (str.charCodeAt(i) & 0xff);
- h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16));
- }
-
- h ^= h >>> 13;
- h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16));
- h ^= h >>> 15;
-
- return h >>> 0;
-}
-
-var renderer$5 = window.renderer;
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-// function genHashCode (str) {
-// var hash = 0;
-// if (str.length == 0) {
-// return hash;
-// }
-// for (var i = 0; i < str.length; i++) {
-// var char = str.charCodeAt(i);
-// hash = ((hash<<5)-hash)+char;
-// hash = hash & hash; // Convert to 32bit integer
-// }
-// return hash;
-// }
-
-function serializeDefines (defines) {
- var str = '';
- for (var i = 0; i < defines.length; i++) {
- str += defines[i].name + defines[i].value;
- }
- return str;
-}
-
-function serializePass (pass) {
- var str = pass._programName + pass._cullMode;
- if (pass._blend) {
- str += pass._blendEq + pass._blendAlphaEq + pass._blendSrc + pass._blendDst
- + pass._blendSrcAlpha + pass._blendDstAlpha + pass._blendColor;
- }
- if (pass._depthTest) {
- str += pass._depthWrite + pass._depthFunc;
- }
- if (pass._stencilTest) {
- str += pass._stencilFuncFront + pass._stencilRefFront + pass._stencilMaskFront
- + pass._stencilFailOpFront + pass._stencilZFailOpFront + pass._stencilZPassOpFront
- + pass._stencilWriteMaskFront
- + pass._stencilFuncBack + pass._stencilRefBack + pass._stencilMaskBack
- + pass._stencilFailOpBack + pass._stencilZFailOpBack + pass._stencilZPassOpBack
- + pass._stencilWriteMaskBack;
- }
- return str;
-}
-
-function computeHash(material) {
- var effect = material._effect;
- var hashData = '';
- if (effect) {
- var i, j, techData, param, prop, propKey;
-
- // effect._defines
- hashData += serializeDefines(effect._defines);
- // effect._techniques
- for (i = 0; i < effect._techniques.length; i++) {
- techData = effect._techniques[i];
- // technique.stageIDs
- hashData += techData.stageIDs;
- // technique._layer
- // hashData += + techData._layer + "_";
- // technique.passes
- for (j = 0; j < techData.passes.length; j++) {
- hashData += serializePass(techData.passes[j]);
- }
- //technique._parameters
- for (j = 0; j < techData._parameters.length; j++) {
- param = techData._parameters[j];
- propKey = param.name;
- prop = effect._properties[propKey];
- if (!prop) {
- continue;
- }
- switch(param.type) {
- case renderer$5.PARAM_INT:
- case renderer$5.PARAM_FLOAT:
- hashData += prop + ';';
- break;
- case renderer$5.PARAM_INT2:
- case renderer$5.PARAM_FLOAT2:
- hashData += prop.x + ',' + prop.y + ';';
- break;
- case renderer$5.PARAM_INT4:
- case renderer$5.PARAM_FLOAT4:
- hashData += prop.x + ',' + prop.y + ',' + prop.z + ',' + prop.w + ';';
- break;
- case renderer$5.PARAM_COLOR4:
- hashData += prop.r + ',' + prop.g + ',' + prop.b + ',' + prop.a + ';';
- break;
- case renderer$5.PARAM_MAT2:
- hashData += prop.m00 + ',' + prop.m01 + ',' + prop.m02 + ',' + prop.m03 + ';';
- break;
- case renderer$5.PARAM_TEXTURE_2D:
- case renderer$5.PARAM_TEXTURE_CUBE:
- hashData += material._texIds[propKey] + ';';
- break;
- case renderer$5.PARAM_INT3:
- case renderer$5.PARAM_FLOAT3:
- case renderer$5.PARAM_COLOR3:
- case renderer$5.PARAM_MAT3:
- case renderer$5.PARAM_MAT4:
- hashData += JSON.stringify(prop) + ';';
- break;
- default:
- break;
- }
- }
- }
- }
- return hashData ? murmurhash2_32_gc(hashData, 666) : hashData;
-}
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var Material = (function (Asset$$1) {
- function Material(persist) {
- if ( persist === void 0 ) persist = false;
-
- Asset$$1.call(this, persist);
-
- this._effect = null; // renderer.Effect
- this._texIds = {}; // ids collected from texture defines
- this._hash = '';
- }
-
- if ( Asset$$1 ) Material.__proto__ = Asset$$1;
- Material.prototype = Object.create( Asset$$1 && Asset$$1.prototype );
- Material.prototype.constructor = Material;
-
- var prototypeAccessors = { hash: { configurable: true } };
-
- prototypeAccessors.hash.get = function () {
- return this._hash;
- };
-
- Material.prototype.updateHash = function updateHash (value) {
- this._hash = value || computeHash(this);
- };
-
- Object.defineProperties( Material.prototype, prototypeAccessors );
-
- return Material;
-}(Asset));
-
-var gfx$5 = window.gfx;
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var SpriteMaterial = (function (Material$$1) {
- function SpriteMaterial() {
- Material$$1.call(this, false);
-
- var pass = new renderer$5.Pass('sprite');
- pass.setDepth(false, false);
- pass.setCullMode(gfx$5.CULL_NONE);
- pass.setBlend(
- gfx$5.BLEND_FUNC_ADD,
- gfx$5.BLEND_SRC_ALPHA, gfx$5.BLEND_ONE_MINUS_SRC_ALPHA,
- gfx$5.BLEND_FUNC_ADD,
- gfx$5.BLEND_SRC_ALPHA, gfx$5.BLEND_ONE_MINUS_SRC_ALPHA
- );
-
- var mainTech = new renderer$5.Technique(
- ['transparent'],
- [
- { name: 'texture', type: renderer$5.PARAM_TEXTURE_2D },
- { name: 'color', type: renderer$5.PARAM_COLOR4 } ],
- [
- pass
- ]
- );
-
- this._color = {r: 1, g: 1, b: 1, a: 1};
- this._effect = new renderer$5.Effect(
- [
- mainTech ],
- {
- 'color': this._color
- },
- [
- { name: 'useTexture', value: true },
- { name: 'useModel', value: false },
- { name: 'alphaTest', value: false },
- { name: 'use2DPos', value: true },
- { name: 'useColor', value: true } ]
- );
-
- this._mainTech = mainTech;
- this._texture = null;
- }
-
- if ( Material$$1 ) SpriteMaterial.__proto__ = Material$$1;
- SpriteMaterial.prototype = Object.create( Material$$1 && Material$$1.prototype );
- SpriteMaterial.prototype.constructor = SpriteMaterial;
-
- var prototypeAccessors = { effect: { configurable: true },useTexture: { configurable: true },useModel: { configurable: true },use2DPos: { configurable: true },useColor: { configurable: true },texture: { configurable: true },color: { configurable: true } };
-
- prototypeAccessors.effect.get = function () {
- return this._effect;
- };
-
- prototypeAccessors.useTexture.get = function () {
- this._effect.getDefine('useTexture');
- };
-
- prototypeAccessors.useTexture.set = function (val) {
- this._effect.define('useTexture', val);
- };
-
- prototypeAccessors.useModel.get = function () {
- this._effect.getDefine('useModel');
- };
-
- prototypeAccessors.useModel.set = function (val) {
- this._effect.define('useModel', val);
- };
-
- prototypeAccessors.use2DPos.get = function () {
- this._effect.getDefine('use2DPos');
- };
-
- prototypeAccessors.use2DPos.set = function (val) {
- this._effect.define('use2DPos', val);
- };
-
- prototypeAccessors.useColor.get = function () {
- this._effect.getDefine('useColor');
- };
-
- prototypeAccessors.useColor.set = function (val) {
- this._effect.define('useColor', val);
- };
-
- prototypeAccessors.texture.get = function () {
- return this._texture;
- };
-
- prototypeAccessors.texture.set = function (val) {
- if (this._texture !== val) {
- this._texture = val;
- this._effect.setProperty('texture', val.getImpl());
- this._texIds['texture'] = val.getId();
- }
- };
-
- prototypeAccessors.color.get = function () {
- return this._color;
- };
-
- prototypeAccessors.color.set = function (val) {
- var color = this._color;
- color.r = val.r / 255;
- color.g = val.g / 255;
- color.b = val.b / 255;
- color.a = val.a / 255;
- this._effect.setProperty('color', color);
- };
-
- SpriteMaterial.prototype.clone = function clone () {
- var copy = new SpriteMaterial();
- copy.texture = this.texture;
- copy.useTexture = this.useTexture;
- copy.useModel = this.useModel;
- copy.use2DPos = this.use2DPos;
- copy.useColor = this.useColor;
- copy.updateHash();
- return copy;
- };
-
- Object.defineProperties( SpriteMaterial.prototype, prototypeAccessors );
-
- return SpriteMaterial;
-}(Material));
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var GraySpriteMaterial = (function (Material$$1) {
- function GraySpriteMaterial() {
- Material$$1.call(this, false);
-
- var pass = new renderer$5.Pass('gray_sprite');
- pass.setDepth(false, false);
- pass.setCullMode(gfx$5.CULL_NONE);
- pass.setBlend(
- gfx$5.BLEND_FUNC_ADD,
- gfx$5.BLEND_SRC_ALPHA, gfx$5.BLEND_ONE_MINUS_SRC_ALPHA,
- gfx$5.BLEND_FUNC_ADD,
- gfx$5.BLEND_SRC_ALPHA, gfx$5.BLEND_ONE_MINUS_SRC_ALPHA
- );
-
- var mainTech = new renderer$5.Technique(
- ['transparent'],
- [
- { name: 'texture', type: renderer$5.PARAM_TEXTURE_2D },
- { name: 'color', type: renderer$5.PARAM_COLOR4 } ],
- [
- pass
- ]
- );
-
- this._color = {r: 1, g: 1, b: 1, a: 1};
- this._effect = new renderer$5.Effect(
- [
- mainTech ],
- {
- 'color': this._color
- },
- []
- );
-
- this._mainTech = mainTech;
- this._texture = null;
- }
-
- if ( Material$$1 ) GraySpriteMaterial.__proto__ = Material$$1;
- GraySpriteMaterial.prototype = Object.create( Material$$1 && Material$$1.prototype );
- GraySpriteMaterial.prototype.constructor = GraySpriteMaterial;
-
- var prototypeAccessors = { effect: { configurable: true },texture: { configurable: true },color: { configurable: true } };
-
- prototypeAccessors.effect.get = function () {
- return this._effect;
- };
-
- prototypeAccessors.texture.get = function () {
- return this._texture;
- };
-
- prototypeAccessors.texture.set = function (val) {
- if (this._texture !== val) {
- this._texture = val;
- this._effect.setProperty('texture', val.getImpl());
- this._texIds['texture'] = val.getId();
- }
- };
-
- prototypeAccessors.color.get = function () {
- return this._color;
- };
-
- prototypeAccessors.color.set = function (val) {
- var color = this._color;
- color.r = val.r / 255;
- color.g = val.g / 255;
- color.b = val.b / 255;
- color.a = val.a / 255;
- this._effect.setProperty('color', color);
- };
-
- GraySpriteMaterial.prototype.clone = function clone () {
- var copy = new GraySpriteMaterial();
- copy.texture = this.texture;
- copy.color = this.color;
- copy.updateHash();
- return copy;
- };
-
- Object.defineProperties( GraySpriteMaterial.prototype, prototypeAccessors );
-
- return GraySpriteMaterial;
-}(Material));
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var StencilMaterial = (function (Material$$1) {
- function StencilMaterial() {
- Material$$1.call(this, false);
-
- this._pass = new renderer$5.Pass('sprite');
- this._pass.setDepth(false, false);
- this._pass.setCullMode(gfx$5.CULL_NONE);
- this._pass.setBlend(
- gfx$5.BLEND_FUNC_ADD,
- gfx$5.BLEND_SRC_ALPHA, gfx$5.BLEND_ONE_MINUS_SRC_ALPHA,
- gfx$5.BLEND_FUNC_ADD,
- gfx$5.BLEND_SRC_ALPHA, gfx$5.BLEND_ONE_MINUS_SRC_ALPHA
- );
-
- var mainTech = new renderer$5.Technique(
- ['transparent'],
- [
- { name: 'texture', type: renderer$5.PARAM_TEXTURE_2D },
- { name: 'alphaThreshold', type: renderer$5.PARAM_FLOAT },
- { name: 'color', type: renderer$5.PARAM_COLOR4 } ],
- [
- this._pass
- ]
- );
-
- this._effect = new renderer$5.Effect(
- [
- mainTech ],
- {
- 'color': {r: 1, g: 1, b: 1, a: 1}
- },
- [
- { name: 'useTexture', value: true },
- { name: 'useModel', value: false },
- { name: 'alphaTest', value: true },
- { name: 'use2DPos', value: true },
- { name: 'useColor', value: true } ]
- );
-
- this._mainTech = mainTech;
- this._texture = null;
- }
-
- if ( Material$$1 ) StencilMaterial.__proto__ = Material$$1;
- StencilMaterial.prototype = Object.create( Material$$1 && Material$$1.prototype );
- StencilMaterial.prototype.constructor = StencilMaterial;
-
- var prototypeAccessors = { effect: { configurable: true },useTexture: { configurable: true },useModel: { configurable: true },useColor: { configurable: true },texture: { configurable: true },alphaThreshold: { configurable: true } };
-
- prototypeAccessors.effect.get = function () {
- return this._effect;
- };
-
- prototypeAccessors.useTexture.get = function () {
- this._effect.getDefine('useTexture');
- };
-
- prototypeAccessors.useTexture.set = function (val) {
- this._effect.define('useTexture', val);
- };
-
- prototypeAccessors.useModel.get = function () {
- this._effect.getDefine('useModel');
- };
-
- prototypeAccessors.useModel.set = function (val) {
- this._effect.define('useModel', val);
- };
-
- prototypeAccessors.useColor.get = function () {
- this._effect.getDefine('useColor');
- };
-
- prototypeAccessors.useColor.set = function (val) {
- this._effect.define('useColor', val);
- };
-
- prototypeAccessors.texture.get = function () {
- return this._texture;
- };
-
- prototypeAccessors.texture.set = function (val) {
- if (this._texture !== val) {
- this._texture = val;
- this._effect.setProperty('texture', val.getImpl());
- this._texIds['texture'] = val.getId();
- }
- };
-
- prototypeAccessors.alphaThreshold.get = function () {
- return this._effect.getProperty('alphaThreshold');
- };
-
- prototypeAccessors.alphaThreshold.set = function (val) {
- this._effect.setProperty('alphaThreshold', val);
- };
-
- StencilMaterial.prototype.clone = function clone () {
- var copy = new StencilMaterial();
- copy.useTexture = this.useTexture;
- copy.useModel = this.useModel;
- copy.useColor = this.useColor;
- copy.texture = this.texture;
- copy.alphaThreshold = this.alphaThreshold;
- copy.updateHash();
- return copy;
- };
-
- Object.defineProperties( StencilMaterial.prototype, prototypeAccessors );
-
- return StencilMaterial;
-}(Material));
-
-var _d2r = Math.PI / 180.0;
-var _r2d = 180.0 / Math.PI;
-
-/**
- * @property {number} EPSILON
- */
-var EPSILON = 0.000001;
-
-/**
- * Tests whether or not the arguments have approximately the same value, within an absolute
- * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less
- * than or equal to 1.0, and a relative tolerance is used for larger values)
- *
- * @param {Number} a The first number to test.
- * @param {Number} b The second number to test.
- * @returns {Boolean} True if the numbers are approximately equal, false otherwise.
- */
-function equals(a, b) {
- return Math.abs(a - b) <= EPSILON * Math.max(1.0, Math.abs(a), Math.abs(b));
-}
-
-/**
- * Tests whether or not the arguments have approximately the same value by given maxDiff
- *
- * @param {Number} a The first number to test.
- * @param {Number} b The second number to test.
- * @param {Number} maxDiff Maximum difference.
- * @returns {Boolean} True if the numbers are approximately equal, false otherwise.
- */
-function approx(a, b, maxDiff) {
- maxDiff = maxDiff || EPSILON;
- return Math.abs(a - b) <= maxDiff;
-}
-
-/**
- * Clamps a value between a minimum float and maximum float value.
- *
- * @method clamp
- * @param {number} val
- * @param {number} min
- * @param {number} max
- * @return {number}
- */
-function clamp(val, min, max) {
- return val < min ? min : val > max ? max : val;
-}
-
-/**
- * Clamps a value between 0 and 1.
- *
- * @method clamp01
- * @param {number} val
- * @return {number}
- */
-function clamp01(val) {
- return val < 0 ? 0 : val > 1 ? 1 : val;
-}
-
-/**
- * @method lerp
- * @param {number} from
- * @param {number} to
- * @param {number} ratio - the interpolation coefficient
- * @return {number}
- */
-function lerp(from, to, ratio) {
- return from + (to - from) * ratio;
-}
-
-/**
-* Convert Degree To Radian
-*
-* @param {Number} a Angle in Degrees
-*/
-function toRadian(a) {
- return a * _d2r;
-}
-
-/**
-* Convert Radian To Degree
-*
-* @param {Number} a Angle in Radian
-*/
-function toDegree(a) {
- return a * _r2d;
-}
-
-/**
-* @method random
-*/
-var random = Math.random;
-
-/**
- * Returns a floating-point random number between min (inclusive) and max (exclusive).
- *
- * @method randomRange
- * @param {number} min
- * @param {number} max
- * @return {number} the random number
- */
-function randomRange(min, max) {
- return Math.random() * (max - min) + min;
-}
-
-/**
- * Returns a random integer between min (inclusive) and max (exclusive).
- *
- * @method randomRangeInt
- * @param {number} min
- * @param {number} max
- * @return {number} the random integer
- */
-function randomRangeInt(min, max) {
- return Math.floor(randomRange(min, max));
-}
-
-/**
- * Returns the next power of two for the value
- *
- * @method nextPow2
- * @param {number} val
- * @return {number} the the next power of two
- */
-function nextPow2(val) {
- --val;
- val = (val >> 1) | val;
- val = (val >> 2) | val;
- val = (val >> 4) | val;
- val = (val >> 8) | val;
- val = (val >> 16) | val;
- ++val;
-
- return val;
-}
-
-/**
- * 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;
-var INT_MAX = 0x7fffffff;
-var INT_MIN = -1<<(INT_BITS-1);
-
-/**
- * Returns -1, 0, +1 depending on sign of x
- *
- * @param {number} v
- * @returns {number}
- */
-function sign(v) {
- return (v > 0) - (v < 0);
-}
-
-/**
- * Computes absolute value of integer
- *
- * @param {number} v
- * @returns {number}
- */
-function abs(v) {
- var mask = v >> (INT_BITS-1);
- return (v ^ mask) - mask;
-}
-
-/**
- * Computes minimum of integers x and y
- *
- * @param {number} x
- * @param {number} y
- * @returns {number}
- */
-function min(x, y) {
- return y ^ ((x ^ y) & -(x < y));
-}
-
-/**
- * Computes maximum of integers x and y
- *
- * @param {number} x
- * @param {number} y
- * @returns {number}
- */
-function max(x, y) {
- return x ^ ((x ^ y) & -(x < y));
-}
-
-/**
- * Checks if a number is a power of two
- *
- * @param {number} v
- * @returns {boolean}
- */
-function isPow2(v) {
- return !(v & (v-1)) && (!!v);
-}
-
-/**
- * Computes log base 2 of v
- *
- * @param {number} v
- * @returns {number}
- */
-function log2(v) {
- var r, shift;
- r = (v > 0xFFFF) << 4; v >>>= r;
- shift = (v > 0xFF ) << 3; v >>>= shift; r |= shift;
- shift = (v > 0xF ) << 2; v >>>= shift; r |= shift;
- shift = (v > 0x3 ) << 1; v >>>= shift; r |= shift;
- return r | (v >> 1);
-}
-
-/**
- * Computes log base 10 of v
- *
- * @param {number} v
- * @returns {number}
- */
-function log10$1(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
- *
- * @param {number} v
- * @returns {number}
- */
-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
- *
- * @param {number} v
- * @returns {number}
- */
-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
- *
- * @param {number} v
- * @returns {number}
- */
-function nextPow2$1(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
- *
- * @param {number} v
- * @returns {number}
- */
-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
- *
- * @param {number} v
- * @returns {number}
- */
-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
- *
- * @param {number} v
- * @returns {number}
- */
-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
- *
- * @param {number} x
- * @param {number} y
- * @returns {number}
- */
-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
- *
- * @param {number} v
- * @param {number} n
- * @returns {number}
- */
-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
- *
- * @param {number} x
- * @param {number} y
- * @param {number} z
- * @returns {number}
- */
-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
- *
- * @param {number} v
- * @param {number} n
- * @returns {number}
- */
-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)
- *
- * @param {number} v
- * @returns {number}
- */
-function nextCombination(v) {
- var t = v | (v - 1);
- return (t + 1) | (((~t & -~t) - 1) >>> (countTrailingZeros(v) + 1));
-}
-
-var bits_ = Object.freeze({
- INT_BITS: INT_BITS,
- INT_MAX: INT_MAX,
- INT_MIN: INT_MIN,
- sign: sign,
- abs: abs,
- min: min,
- max: max,
- isPow2: isPow2,
- log2: log2,
- log10: log10$1,
- popCount: popCount,
- countTrailingZeros: countTrailingZeros,
- nextPow2: nextPow2$1,
- prevPow2: prevPow2,
- parity: parity,
- reverse: reverse,
- interleave2: interleave2,
- deinterleave2: deinterleave2,
- interleave3: interleave3,
- deinterleave3: deinterleave3,
- nextCombination: nextCombination
-});
-
-var _tmp = new Array(2);
-
-var _vec2 = function _vec2(x, y) {
- this.x = x;
- this.y = y;
-};
-
-_vec2.prototype.toJSON = function toJSON () {
- _tmp[0] = this.x;
- _tmp[1] = this.y;
-
- return _tmp;
-};
-
-/**
- * @class 2 Dimensional Vector
- * @name vec2
- */
-var vec2 = {};
-
-/**
- * Creates a new, empty vec2
- *
- * @returns {vec2} a new 2D vector
- */
-vec2.create = function () {
- return new _vec2(0, 0);
-};
-
-/**
- * Creates a new vec2 initialized with the given values
- *
- * @param {Number} x X component
- * @param {Number} y Y component
- * @returns {vec2} a new 2D vector
- */
-vec2.new = function (x, y) {
- return new _vec2(x, y);
-};
-
-/**
- * Creates a new vec2 initialized with values from an existing vector
- *
- * @param {vec2} a vector to clone
- * @returns {vec2} a new 2D vector
- */
-vec2.clone = function (a) {
- return new _vec2(a.x, a.y);
-};
-
-/**
- * Copy the values from one vec2 to another
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the source vector
- * @returns {vec2} out
- */
-vec2.copy = function (out, a) {
- out.x = a.x;
- out.y = a.y;
- return out;
-};
-
-/**
- * Set the components of a vec2 to the given values
- *
- * @param {vec2} out the receiving vector
- * @param {Number} x X component
- * @param {Number} y Y component
- * @returns {vec2} out
- */
-vec2.set = function (out, x, y) {
- out.x = x;
- out.y = y;
- return out;
-};
-
-/**
- * Adds two vec2's
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
- */
-vec2.add = function (out, a, b) {
- out.x = a.x + b.x;
- out.y = a.y + b.y;
- return out;
-};
-
-/**
- * Subtracts vector b from vector a
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
- */
-vec2.subtract = function (out, a, b) {
- out.x = a.x - b.x;
- out.y = a.y - b.y;
- return out;
-};
-
-/**
- * Alias for {@link vec2.subtract}
- * @function
- */
-vec2.sub = vec2.subtract;
-
-/**
- * Multiplies two vec2's
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
- */
-vec2.multiply = function (out, a, b) {
- out.x = a.x * b.x;
- out.y = a.y * b.y;
- return out;
-};
-
-/**
- * Alias for {@link vec2.multiply}
- * @function
- */
-vec2.mul = vec2.multiply;
-
-/**
- * Divides two vec2's
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
- */
-vec2.divide = function (out, a, b) {
- out.x = a.x / b.x;
- out.y = a.y / b.y;
- return out;
-};
-
-/**
- * Alias for {@link vec2.divide}
- * @function
- */
-vec2.div = vec2.divide;
-
-/**
- * Math.ceil the components of a vec2
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to ceil
- * @returns {vec2} out
- */
-vec2.ceil = function (out, a) {
- out.x = Math.ceil(a.x);
- out.y = Math.ceil(a.y);
- return out;
-};
-
-/**
- * Math.floor the components of a vec2
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to floor
- * @returns {vec2} out
- */
-vec2.floor = function (out, a) {
- out.x = Math.floor(a.x);
- out.y = Math.floor(a.y);
- return out;
-};
-
-/**
- * Returns the minimum of two vec2's
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
- */
-vec2.min = function (out, a, b) {
- out.x = Math.min(a.x, b.x);
- out.y = Math.min(a.y, b.y);
- return out;
-};
-
-/**
- * Returns the maximum of two vec2's
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
- */
-vec2.max = function (out, a, b) {
- out.x = Math.max(a.x, b.x);
- out.y = Math.max(a.y, b.y);
- return out;
-};
-
-/**
- * Math.round the components of a vec2
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to round
- * @returns {vec2} out
- */
-vec2.round = function (out, a) {
- out.x = Math.round(a.x);
- out.y = Math.round(a.y);
- return out;
-};
-
-/**
- * Scales a vec2 by a scalar number
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the vector to scale
- * @param {Number} b amount to scale the vector by
- * @returns {vec2} out
- */
-vec2.scale = function (out, a, b) {
- out.x = a.x * b;
- out.y = a.y * b;
- return out;
-};
-
-/**
- * Adds two vec2's after scaling the second operand by a scalar value
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @param {Number} scale the amount to scale b by before adding
- * @returns {vec2} out
- */
-vec2.scaleAndAdd = function (out, a, b, scale) {
- out.x = a.x + (b.x * scale);
- out.y = a.y + (b.y * scale);
- return out;
-};
-
-/**
- * Calculates the euclidian distance between two vec2's
- *
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {Number} distance between a and b
- */
-vec2.distance = function (a, b) {
- var x = b.x - a.x,
- y = b.y - a.y;
- return Math.sqrt(x * x + y * y);
-};
-
-/**
- * Alias for {@link vec2.distance}
- * @function
- */
-vec2.dist = vec2.distance;
-
-/**
- * Calculates the squared euclidian distance between two vec2's
- *
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {Number} squared distance between a and b
- */
-vec2.squaredDistance = function (a, b) {
- var x = b.x - a.x,
- y = b.y - a.y;
- return x * x + y * y;
-};
-
-/**
- * Alias for {@link vec2.squaredDistance}
- * @function
- */
-vec2.sqrDist = vec2.squaredDistance;
-
-/**
- * Calculates the length of a vec2
- *
- * @param {vec2} a vector to calculate length of
- * @returns {Number} length of a
- */
-vec2.length = function (a) {
- var x = a.x,
- y = a.y;
- return Math.sqrt(x * x + y * y);
-};
-
-/**
- * Alias for {@link vec2.length}
- * @function
- */
-vec2.len = vec2.length;
-
-/**
- * Calculates the squared length of a vec2
- *
- * @param {vec2} a vector to calculate squared length of
- * @returns {Number} squared length of a
- */
-vec2.squaredLength = function (a) {
- var x = a.x,
- y = a.y;
- return x * x + y * y;
-};
-
-/**
- * Alias for {@link vec2.squaredLength}
- * @function
- */
-vec2.sqrLen = vec2.squaredLength;
-
-/**
- * Negates the components of a vec2
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to negate
- * @returns {vec2} out
- */
-vec2.negate = function (out, a) {
- out.x = -a.x;
- out.y = -a.y;
- return out;
-};
-
-/**
- * Returns the inverse of the components of a vec2
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to invert
- * @returns {vec2} out
- */
-vec2.inverse = function (out, a) {
- out.x = 1.0 / a.x;
- out.y = 1.0 / a.y;
- return out;
-};
-
-/**
- * Returns the inverse of the components of a vec2 safely
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to invert
- * @returns {vec2} out
- */
-vec2.inverseSafe = function (out, a) {
- var x = a.x,
- y = a.y;
-
- if (Math.abs(x) < EPSILON) {
- out.x = 0;
- } else {
- out.x = 1.0 / x;
- }
-
- if (Math.abs(y) < EPSILON) {
- out.y = 0;
- } else {
- out.y = 1.0 / a.y;
- }
-
- return out;
-};
-
-/**
- * Normalize a vec2
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to normalize
- * @returns {vec2} out
- */
-vec2.normalize = function (out, a) {
- var x = a.x,
- y = a.y;
- var len = x * x + y * y;
- if (len > 0) {
- //TODO: evaluate use of glm_invsqrt here?
- len = 1 / Math.sqrt(len);
- out.x = a.x * len;
- out.y = a.y * len;
- }
- return out;
-};
-
-/**
- * Calculates the dot product of two vec2's
- *
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {Number} dot product of a and b
- */
-vec2.dot = function (a, b) {
- return a.x * b.x + a.y * b.y;
-};
-
-/**
- * Computes the cross product of two vec2's
- * Note that the cross product must by definition produce a 3D vector
- *
- * @param {vec3} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec3} out
- */
-vec2.cross = function (out, a, b) {
- var z = a.x * b.y - a.y * b.x;
- out.x = out.y = 0;
- out.z = z;
- return out;
-};
-
-/**
- * Performs a linear interpolation between two vec2's
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {vec2} out
- */
-vec2.lerp = function (out, a, b, t) {
- var ax = a.x,
- ay = a.y;
- out.x = ax + t * (b.x - ax);
- out.y = ay + t * (b.y - ay);
- return out;
-};
-
-/**
- * Generates a random vector with the given scale
- *
- * @param {vec2} out the receiving vector
- * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
- * @returns {vec2} out
- */
-vec2.random = function (out, scale) {
- scale = scale || 1.0;
- var r = random() * 2.0 * Math.PI;
- out.x = Math.cos(r) * scale;
- out.y = Math.sin(r) * scale;
- return out;
-};
-
-/**
- * Transforms the vec2 with a mat2
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the vector to transform
- * @param {mat2} m matrix to transform with
- * @returns {vec2} out
- */
-vec2.transformMat2 = function (out, a, m) {
- var x = a.x,
- y = a.y;
- out.x = m.m00 * x + m.m02 * y;
- out.y = m.m01 * x + m.m03 * y;
- return out;
-};
-
-/**
- * Transforms the vec2 with a mat23
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the vector to transform
- * @param {mat23} m matrix to transform with
- * @returns {vec2} out
- */
-vec2.transformMat23 = function (out, a, m) {
- var x = a.x,
- y = a.y;
- out.x = m.m00 * x + m.m02 * y + m.m04;
- out.y = m.m01 * x + m.m03 * y + m.m05;
- return out;
-};
-
-/**
- * Transforms the vec2 with a mat3
- * 3rd vector component is implicitly '1'
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the vector to transform
- * @param {mat3} m matrix to transform with
- * @returns {vec2} out
- */
-vec2.transformMat3 = function (out, a, m) {
- var x = a.x,
- y = a.y;
- out.x = m.m00 * x + m.m03 * y + m.m06;
- out.y = m.m01 * x + m.m04 * y + m.m07;
- return out;
-};
-
-/**
- * Transforms the vec2 with a mat4
- * 3rd vector component is implicitly '0'
- * 4th vector component is implicitly '1'
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the vector to transform
- * @param {mat4} m matrix to transform with
- * @returns {vec2} out
- */
-vec2.transformMat4 = function (out, a, m) {
- var x = a.x,
- y = a.y;
- out.x = m.m00 * x + m.m04 * y + m.m12;
- out.y = m.m01 * x + m.m05 * y + m.m13;
- return out;
-};
-
-/**
- * Perform some operation over an array of vec2s.
- *
- * @param {Array} a the array of vectors to iterate over
- * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
- * @param {Number} offset Number of elements to skip at the beginning of the array
- * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
- * @param {Function} fn Function to call for each vector in the array
- * @param {Object} [arg] additional argument to pass to fn
- * @returns {Array} a
- * @function
- */
-vec2.forEach = (function () {
- var vec = vec2.create();
-
- return function (a, stride, offset, count, fn, arg) {
- var i, l;
- if (!stride) {
- stride = 2;
- }
-
- if (!offset) {
- offset = 0;
- }
-
- if (count) {
- l = Math.min((count * stride) + offset, a.length);
- } else {
- l = a.length;
- }
-
- for (i = offset; i < l; i += stride) {
- vec.x = a[i]; vec.y = a[i + 1];
- fn(vec, vec, arg);
- a[i] = vec.x; a[i + 1] = vec.y;
- }
-
- return a;
- };
-})();
-
-/**
- * Returns a string representation of a vector
- *
- * @param {vec2} a vector to represent as a string
- * @returns {String} string representation of the vector
- */
-vec2.str = function (a) {
- return ("vec2(" + (a.x) + ", " + (a.y) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {vec2} v
- * @returns {array}
- */
-vec2.array = function (out, v) {
- out[0] = v.x;
- out[1] = v.y;
-
- return out;
-};
-
-/**
- * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)
- *
- * @param {vec2} a The first vector.
- * @param {vec2} b The second vector.
- * @returns {Boolean} True if the vectors are equal, false otherwise.
- */
-vec2.exactEquals = function (a, b) {
- return a.x === b.x && a.y === b.y;
-};
-
-/**
- * Returns whether or not the vectors have approximately the same elements in the same position.
- *
- * @param {vec2} a The first vector.
- * @param {vec2} b The second vector.
- * @returns {Boolean} True if the vectors are equal, false otherwise.
- */
-vec2.equals = function (a, b) {
- var a0 = a.x, a1 = a.y;
- var b0 = b.x, b1 = b.y;
- return (Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)));
-};
-
-var _tmp$1 = new Array(3);
-
-var _vec3 = function _vec3(x, y, z) {
- this.x = x;
- this.y = y;
- this.z = z;
-};
-
-_vec3.prototype.toJSON = function toJSON () {
- _tmp$1[0] = this.x;
- _tmp$1[1] = this.y;
- _tmp$1[2] = this.z;
-
- return _tmp$1;
-};
-
-/**
- * @class 3 Dimensional Vector
- * @name vec3
- */
-var vec3 = {};
-
-/**
- * Creates a new, empty vec3
- *
- * @returns {vec3} a new 3D vector
- */
-vec3.create = function () {
- return new _vec3(0, 0, 0);
-};
-
-/**
- * Creates a new vec3 initialized with the given values
- *
- * @param {Number} x X component
- * @param {Number} y Y component
- * @param {Number} z Z component
- * @returns {vec3} a new 3D vector
- */
-vec3.new = function (x, y, z) {
- return new _vec3(x, y, z);
-};
-
-/**
- * Creates a new vec3 initialized with values from an existing vector
- *
- * @param {vec3} a vector to clone
- * @returns {vec3} a new 3D vector
- */
-vec3.clone = function (a) {
- return new _vec3(a.x, a.y, a.z);
-};
-
-/**
- * Copy the values from one vec3 to another
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the source vector
- * @returns {vec3} out
- */
-vec3.copy = function (out, a) {
- out.x = a.x;
- out.y = a.y;
- out.z = a.z;
- return out;
-};
-
-/**
- * Set the components of a vec3 to the given values
- *
- * @param {vec3} out the receiving vector
- * @param {Number} x X component
- * @param {Number} y Y component
- * @param {Number} z Z component
- * @returns {vec3} out
- */
-vec3.set = function (out, x, y, z) {
- out.x = x;
- out.y = y;
- out.z = z;
- return out;
-};
-
-/**
- * Adds two vec3's
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.add = function (out, a, b) {
- out.x = a.x + b.x;
- out.y = a.y + b.y;
- out.z = a.z + b.z;
- return out;
-};
-
-/**
- * Subtracts vector b from vector a
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.subtract = function (out, a, b) {
- out.x = a.x - b.x;
- out.y = a.y - b.y;
- out.z = a.z - b.z;
- return out;
-};
-
-/**
- * Alias for {@link vec3.subtract}
- * @function
- */
-vec3.sub = vec3.subtract;
-
-/**
- * Multiplies two vec3's
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.multiply = function (out, a, b) {
- out.x = a.x * b.x;
- out.y = a.y * b.y;
- out.z = a.z * b.z;
- return out;
-};
-
-/**
- * Alias for {@link vec3.multiply}
- * @function
- */
-vec3.mul = vec3.multiply;
-
-/**
- * Divides two vec3's
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.divide = function (out, a, b) {
- out.x = a.x / b.x;
- out.y = a.y / b.y;
- out.z = a.z / b.z;
- return out;
-};
-
-/**
- * Alias for {@link vec3.divide}
- * @function
- */
-vec3.div = vec3.divide;
-
-/**
- * Math.ceil the components of a vec3
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a vector to ceil
- * @returns {vec3} out
- */
-vec3.ceil = function (out, a) {
- out.x = Math.ceil(a.x);
- out.y = Math.ceil(a.y);
- out.z = Math.ceil(a.z);
- return out;
-};
-
-/**
- * Math.floor the components of a vec3
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a vector to floor
- * @returns {vec3} out
- */
-vec3.floor = function (out, a) {
- out.x = Math.floor(a.x);
- out.y = Math.floor(a.y);
- out.z = Math.floor(a.z);
- return out;
-};
-
-/**
- * Returns the minimum of two vec3's
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.min = function (out, a, b) {
- out.x = Math.min(a.x, b.x);
- out.y = Math.min(a.y, b.y);
- out.z = Math.min(a.z, b.z);
- return out;
-};
-
-/**
- * Returns the maximum of two vec3's
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.max = function (out, a, b) {
- out.x = Math.max(a.x, b.x);
- out.y = Math.max(a.y, b.y);
- out.z = Math.max(a.z, b.z);
- return out;
-};
-
-/**
- * Math.round the components of a vec3
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a vector to round
- * @returns {vec3} out
- */
-vec3.round = function (out, a) {
- out.x = Math.round(a.x);
- out.y = Math.round(a.y);
- out.z = Math.round(a.z);
- return out;
-};
-
-/**
- * Scales a vec3 by a scalar number
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the vector to scale
- * @param {Number} b amount to scale the vector by
- * @returns {vec3} out
- */
-vec3.scale = function (out, a, b) {
- out.x = a.x * b;
- out.y = a.y * b;
- out.z = a.z * b;
- return out;
-};
-
-/**
- * Adds two vec3's after scaling the second operand by a scalar value
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @param {Number} scale the amount to scale b by before adding
- * @returns {vec3} out
- */
-vec3.scaleAndAdd = function (out, a, b, scale) {
- out.x = a.x + (b.x * scale);
- out.y = a.y + (b.y * scale);
- out.z = a.z + (b.z * scale);
- return out;
-};
-
-/**
- * Calculates the euclidian distance between two vec3's
- *
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {Number} distance between a and b
- */
-vec3.distance = function (a, b) {
- var x = b.x - a.x,
- y = b.y - a.y,
- z = b.z - a.z;
- return Math.sqrt(x * x + y * y + z * z);
-};
-
-/**
- * Alias for {@link vec3.distance}
- * @function
- */
-vec3.dist = vec3.distance;
-
-/**
- * Calculates the squared euclidian distance between two vec3's
- *
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {Number} squared distance between a and b
- */
-vec3.squaredDistance = function (a, b) {
- var x = b.x - a.x,
- y = b.y - a.y,
- z = b.z - a.z;
- return x * x + y * y + z * z;
-};
-
-/**
- * Alias for {@link vec3.squaredDistance}
- * @function
- */
-vec3.sqrDist = vec3.squaredDistance;
-
-/**
- * Calculates the length of a vec3
- *
- * @param {vec3} a vector to calculate length of
- * @returns {Number} length of a
- */
-vec3.length = function (a) {
- var x = a.x,
- y = a.y,
- z = a.z;
- return Math.sqrt(x * x + y * y + z * z);
-};
-
-/**
- * Alias for {@link vec3.length}
- * @function
- */
-vec3.len = vec3.length;
-
-/**
- * Calculates the squared length of a vec3
- *
- * @param {vec3} a vector to calculate squared length of
- * @returns {Number} squared length of a
- */
-vec3.squaredLength = function (a) {
- var x = a.x,
- y = a.y,
- z = a.z;
- return x * x + y * y + z * z;
-};
-
-/**
- * Alias for {@link vec3.squaredLength}
- * @function
- */
-vec3.sqrLen = vec3.squaredLength;
-
-/**
- * Negates the components of a vec3
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a vector to negate
- * @returns {vec3} out
- */
-vec3.negate = function (out, a) {
- out.x = -a.x;
- out.y = -a.y;
- out.z = -a.z;
- return out;
-};
-
-/**
- * Returns the inverse of the components of a vec3
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a vector to invert
- * @returns {vec3} out
- */
-vec3.inverse = function (out, a) {
- out.x = 1.0 / a.x;
- out.y = 1.0 / a.y;
- out.z = 1.0 / a.z;
- return out;
-};
-
-/**
- * Returns the inverse of the components of a vec3 safely
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a vector to invert
- * @returns {vec3} out
- */
-vec3.inverseSafe = function (out, a) {
- var x = a.x,
- y = a.y,
- z = a.z;
-
- if (Math.abs(x) < EPSILON) {
- out.x = 0;
- } else {
- out.x = 1.0 / x;
- }
-
- if (Math.abs(y) < EPSILON) {
- out.y = 0;
- } else {
- out.y = 1.0 / y;
- }
-
- if (Math.abs(z) < EPSILON) {
- out.z = 0;
- } else {
- out.z = 1.0 / z;
- }
-
- return out;
-};
-
-/**
- * Normalize a vec3
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a vector to normalize
- * @returns {vec3} out
- */
-vec3.normalize = function (out, a) {
- var x = a.x,
- y = a.y,
- z = a.z;
-
- var len = x * x + y * y + z * z;
- if (len > 0) {
- //TODO: evaluate use of glm_invsqrt here?
- len = 1 / Math.sqrt(len);
- out.x = x * len;
- out.y = y * len;
- out.z = z * len;
- }
- return out;
-};
-
-/**
- * Calculates the dot product of two vec3's
- *
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {Number} dot product of a and b
- */
-vec3.dot = function (a, b) {
- return a.x * b.x + a.y * b.y + a.z * b.z;
-};
-
-/**
- * Computes the cross product of two vec3's
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.cross = function (out, a, b) {
- var ax = a.x, ay = a.y, az = a.z,
- bx = b.x, by = b.y, bz = b.z;
-
- out.x = ay * bz - az * by;
- out.y = az * bx - ax * bz;
- out.z = ax * by - ay * bx;
- return out;
-};
-
-/**
- * Performs a linear interpolation between two vec3's
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {vec3} out
- */
-vec3.lerp = function (out, a, b, t) {
- var ax = a.x,
- ay = a.y,
- az = a.z;
- out.x = ax + t * (b.x - ax);
- out.y = ay + t * (b.y - ay);
- out.z = az + t * (b.z - az);
- return out;
-};
-
-/**
- * Performs a hermite interpolation with two control points
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @param {vec3} c the third operand
- * @param {vec3} d the fourth operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {vec3} out
- */
-vec3.hermite = function (out, a, b, c, d, t) {
- var factorTimes2 = t * t,
- factor1 = factorTimes2 * (2 * t - 3) + 1,
- factor2 = factorTimes2 * (t - 2) + t,
- factor3 = factorTimes2 * (t - 1),
- factor4 = factorTimes2 * (3 - 2 * t);
-
- out.x = a.x * factor1 + b.x * factor2 + c.x * factor3 + d.x * factor4;
- out.y = a.y * factor1 + b.y * factor2 + c.y * factor3 + d.y * factor4;
- out.z = a.z * factor1 + b.z * factor2 + c.z * factor3 + d.z * factor4;
-
- return out;
-};
-
-/**
- * Performs a bezier interpolation with two control points
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @param {vec3} c the third operand
- * @param {vec3} d the fourth operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {vec3} out
- */
-vec3.bezier = function (out, a, b, c, d, t) {
- var inverseFactor = 1 - t,
- inverseFactorTimesTwo = inverseFactor * inverseFactor,
- factorTimes2 = t * t,
- factor1 = inverseFactorTimesTwo * inverseFactor,
- factor2 = 3 * t * inverseFactorTimesTwo,
- factor3 = 3 * factorTimes2 * inverseFactor,
- factor4 = factorTimes2 * t;
-
- out.x = a.x * factor1 + b.x * factor2 + c.x * factor3 + d.x * factor4;
- out.y = a.y * factor1 + b.y * factor2 + c.y * factor3 + d.y * factor4;
- out.z = a.z * factor1 + b.z * factor2 + c.z * factor3 + d.z * factor4;
-
- return out;
-};
-
-/**
- * Generates a random vector with the given scale
- *
- * @param {vec3} out the receiving vector
- * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
- * @returns {vec3} out
- */
-vec3.random = function (out, scale) {
- scale = scale || 1.0;
-
- var r = random() * 2.0 * Math.PI;
- var z = (random() * 2.0) - 1.0;
- var zScale = Math.sqrt(1.0 - z * z) * scale;
-
- out.x = Math.cos(r) * zScale;
- out.y = Math.sin(r) * zScale;
- out.z = z * scale;
- return out;
-};
-
-/**
- * Transforms the vec3 with a mat4.
- * 4th vector component is implicitly '1'
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the vector to transform
- * @param {mat4} m matrix to transform with
- * @returns {vec3} out
- */
-vec3.transformMat4 = function (out, a, m) {
- var x = a.x, y = a.y, z = a.z,
- w = m.m03 * x + m.m07 * y + m.m11 * z + m.m15;
- w = w || 1.0;
- out.x = (m.m00 * x + m.m04 * y + m.m08 * z + m.m12) / w;
- out.y = (m.m01 * x + m.m05 * y + m.m09 * z + m.m13) / w;
- out.z = (m.m02 * x + m.m06 * y + m.m10 * z + m.m14) / w;
- return out;
-};
-
-/**
- * Transforms the vec3 with a mat3.
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the vector to transform
- * @param {mat4} m the 3x3 matrix to transform with
- * @returns {vec3} out
- */
-vec3.transformMat3 = function (out, a, m) {
- var x = a.x, y = a.y, z = a.z;
- out.x = x * m.m00 + y * m.m03 + z * m.m06;
- out.y = x * m.m01 + y * m.m04 + z * m.m07;
- out.z = x * m.m02 + y * m.m05 + z * m.m08;
- return out;
-};
-
-/**
- * Transforms the vec3 with a quat
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the vector to transform
- * @param {quat} q quaternion to transform with
- * @returns {vec3} out
- */
-vec3.transformQuat = function (out, a, q) {
- // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations
-
- var x = a.x, y = a.y, z = a.z;
- var qx = q.x, qy = q.y, qz = q.z, qw = q.w;
-
- // calculate quat * vec
- var ix = qw * x + qy * z - qz * y;
- var iy = qw * y + qz * x - qx * z;
- var iz = qw * z + qx * y - qy * x;
- var iw = -qx * x - qy * y - qz * z;
-
- // calculate result * inverse quat
- out.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
- out.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
- out.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
- return out;
-};
-
-/**
- * Rotate a 3D vector around the x-axis
- * @param {vec3} out The receiving vec3
- * @param {vec3} a The vec3 point to rotate
- * @param {vec3} b The origin of the rotation
- * @param {Number} c The angle of rotation
- * @returns {vec3} out
- */
-vec3.rotateX = function (out, a, b, c) {
- var p = [], r = [];
- // Translate point to the origin
- p.x = a.x - b.x;
- p.y = a.y - b.y;
- p.z = a.z - b.z;
-
- //perform rotation
- r.x = p.x;
- r.y = p.y * Math.cos(c) - p.z * Math.sin(c);
- r.z = p.y * Math.sin(c) + p.z * Math.cos(c);
-
- //translate to correct position
- out.x = r.x + b.x;
- out.y = r.y + b.y;
- out.z = r.z + b.z;
-
- return out;
-};
-
-/**
- * Rotate a 3D vector around the y-axis
- * @param {vec3} out The receiving vec3
- * @param {vec3} a The vec3 point to rotate
- * @param {vec3} b The origin of the rotation
- * @param {Number} c The angle of rotation
- * @returns {vec3} out
- */
-vec3.rotateY = function (out, a, b, c) {
- var p = [], r = [];
- //Translate point to the origin
- p.x = a.x - b.x;
- p.y = a.y - b.y;
- p.z = a.z - b.z;
-
- //perform rotation
- r.x = p.z * Math.sin(c) + p.x * Math.cos(c);
- r.y = p.y;
- r.z = p.z * Math.cos(c) - p.x * Math.sin(c);
-
- //translate to correct position
- out.x = r.x + b.x;
- out.y = r.y + b.y;
- out.z = r.z + b.z;
-
- return out;
-};
-
-/**
- * Rotate a 3D vector around the z-axis
- * @param {vec3} out The receiving vec3
- * @param {vec3} a The vec3 point to rotate
- * @param {vec3} b The origin of the rotation
- * @param {Number} c The angle of rotation
- * @returns {vec3} out
- */
-vec3.rotateZ = function (out, a, b, c) {
- var p = [], r = [];
- //Translate point to the origin
- p.x = a.x - b.x;
- p.y = a.y - b.y;
- p.z = a.z - b.z;
-
- //perform rotation
- r.x = p.x * Math.cos(c) - p.y * Math.sin(c);
- r.y = p.x * Math.sin(c) + p.y * Math.cos(c);
- r.z = p.z;
-
- //translate to correct position
- out.x = r.x + b.x;
- out.y = r.y + b.y;
- out.z = r.z + b.z;
-
- return out;
-};
-
-/**
- * Perform some operation over an array of vec3s.
- *
- * @param {Array} a the array of vectors to iterate over
- * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
- * @param {Number} offset Number of elements to skip at the beginning of the array
- * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
- * @param {Function} fn Function to call for each vector in the array
- * @param {Object} [arg] additional argument to pass to fn
- * @returns {Array} a
- * @function
- */
-vec3.forEach = (function () {
- var vec = vec3.create();
-
- return function (a, stride, offset, count, fn, arg) {
- var i, l;
- if (!stride) {
- stride = 3;
- }
-
- if (!offset) {
- offset = 0;
- }
-
- if (count) {
- l = Math.min((count * stride) + offset, a.length);
- } else {
- l = a.length;
- }
-
- for (i = offset; i < l; i += stride) {
- vec.x = a[i]; vec.y = a[i + 1]; vec.z = a[i + 2];
- fn(vec, vec, arg);
- a[i] = vec.x; a[i + 1] = vec.y; a[i + 2] = vec.z;
- }
-
- return a;
- };
-})();
-
-/**
- * Get the angle between two 3D vectors
- * @param {vec3} a The first operand
- * @param {vec3} b The second operand
- * @returns {Number} The angle in radians
- */
-vec3.angle = (function () {
- var tempA = vec3.create();
- var tempB = vec3.create();
-
- return function (a, b) {
- vec3.copy(tempA, a);
- vec3.copy(tempB, b);
-
- vec3.normalize(tempA, tempA);
- vec3.normalize(tempB, tempB);
-
- var cosine = vec3.dot(tempA, tempB);
-
- if (cosine > 1.0) {
- return 0;
- }
-
- if (cosine < -1.0) {
- return Math.PI;
- }
-
- return Math.acos(cosine);
- };
-})();
-
-/**
- * Returns a string representation of a vector
- *
- * @param {vec3} a vector to represent as a string
- * @returns {String} string representation of the vector
- */
-vec3.str = function (a) {
- return ("vec3(" + (a.x) + ", " + (a.y) + ", " + (a.z) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {vec3} v
- * @returns {array}
- */
-vec3.array = function (out, v) {
- out[0] = v.x;
- out[1] = v.y;
- out[2] = v.z;
-
- return out;
-};
-
-/**
- * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
- *
- * @param {vec3} a The first vector.
- * @param {vec3} b The second vector.
- * @returns {Boolean} True if the vectors are equal, false otherwise.
- */
-vec3.exactEquals = function (a, b) {
- return a.x === b.x && a.y === b.y && a.z === b.z;
-};
-
-/**
- * Returns whether or not the vectors have approximately the same elements in the same position.
- *
- * @param {vec3} a The first vector.
- * @param {vec3} b The second vector.
- * @returns {Boolean} True if the vectors are equal, false otherwise.
- */
-vec3.equals = function (a, b) {
- var a0 = a.x, a1 = a.y, a2 = a.z;
- var b0 = b.x, b1 = b.y, b2 = b.z;
- return (Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
- Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)));
-};
-
-var _tmp$2 = new Array(4);
-
-var _vec4 = function _vec4(x, y, z, w) {
- this.x = x;
- this.y = y;
- this.z = z;
- this.w = w;
-};
-
-_vec4.prototype.toJSON = function toJSON () {
- _tmp$2[0] = this.x;
- _tmp$2[1] = this.y;
- _tmp$2[2] = this.z;
- _tmp$2[3] = this.w;
-
- return _tmp$2;
-};
-
-/**
- * @class 4 Dimensional Vector
- * @name vec4
- */
-var vec4 = {};
-
-/**
- * Creates a new, empty vec4
- *
- * @returns {vec4} a new 4D vector
- */
-vec4.create = function () {
- return new _vec4(0, 0, 0, 0);
-};
-
-/**
- * Creates a new vec4 initialized with the given values
- *
- * @param {Number} x X component
- * @param {Number} y Y component
- * @param {Number} z Z component
- * @param {Number} w W component
- * @returns {vec4} a new 4D vector
- */
-vec4.new = function (x, y, z, w) {
- return new _vec4(x, y, z, w);
-};
-
-/**
- * Creates a new vec4 initialized with values from an existing vector
- *
- * @param {vec4} a vector to clone
- * @returns {vec4} a new 4D vector
- */
-vec4.clone = function (a) {
- return new _vec4(a.x, a.y, a.z, a.w);
-};
-
-/**
- * Copy the values from one vec4 to another
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the source vector
- * @returns {vec4} out
- */
-vec4.copy = function (out, a) {
- out.x = a.x;
- out.y = a.y;
- out.z = a.z;
- out.w = a.w;
- return out;
-};
-
-/**
- * Set the components of a vec4 to the given values
- *
- * @param {vec4} out the receiving vector
- * @param {Number} x X component
- * @param {Number} y Y component
- * @param {Number} z Z component
- * @param {Number} w W component
- * @returns {vec4} out
- */
-vec4.set = function (out, x, y, z, w) {
- out.x = x;
- out.y = y;
- out.z = z;
- out.w = w;
- return out;
-};
-
-/**
- * Adds two vec4's
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {vec4} out
- */
-vec4.add = function (out, a, b) {
- out.x = a.x + b.x;
- out.y = a.y + b.y;
- out.z = a.z + b.z;
- out.w = a.w + b.w;
- return out;
-};
-
-/**
- * Subtracts vector b from vector a
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {vec4} out
- */
-vec4.subtract = function (out, a, b) {
- out.x = a.x - b.x;
- out.y = a.y - b.y;
- out.z = a.z - b.z;
- out.w = a.w - b.w;
- return out;
-};
-
-/**
- * Alias for {@link vec4.subtract}
- * @function
- */
-vec4.sub = vec4.subtract;
-
-/**
- * Multiplies two vec4's
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {vec4} out
- */
-vec4.multiply = function (out, a, b) {
- out.x = a.x * b.x;
- out.y = a.y * b.y;
- out.z = a.z * b.z;
- out.w = a.w * b.w;
- return out;
-};
-
-/**
- * Alias for {@link vec4.multiply}
- * @function
- */
-vec4.mul = vec4.multiply;
-
-/**
- * Divides two vec4's
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {vec4} out
- */
-vec4.divide = function (out, a, b) {
- out.x = a.x / b.x;
- out.y = a.y / b.y;
- out.z = a.z / b.z;
- out.w = a.w / b.w;
- return out;
-};
-
-/**
- * Alias for {@link vec4.divide}
- * @function
- */
-vec4.div = vec4.divide;
-
-/**
- * Math.ceil the components of a vec4
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a vector to ceil
- * @returns {vec4} out
- */
-vec4.ceil = function (out, a) {
- out.x = Math.ceil(a.x);
- out.y = Math.ceil(a.y);
- out.z = Math.ceil(a.z);
- out.w = Math.ceil(a.w);
- return out;
-};
-
-/**
- * Math.floor the components of a vec4
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a vector to floor
- * @returns {vec4} out
- */
-vec4.floor = function (out, a) {
- out.x = Math.floor(a.x);
- out.y = Math.floor(a.y);
- out.z = Math.floor(a.z);
- out.w = Math.floor(a.w);
- return out;
-};
-
-/**
- * Returns the minimum of two vec4's
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {vec4} out
- */
-vec4.min = function (out, a, b) {
- out.x = Math.min(a.x, b.x);
- out.y = Math.min(a.y, b.y);
- out.z = Math.min(a.z, b.z);
- out.w = Math.min(a.w, b.w);
- return out;
-};
-
-/**
- * Returns the maximum of two vec4's
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {vec4} out
- */
-vec4.max = function (out, a, b) {
- out.x = Math.max(a.x, b.x);
- out.y = Math.max(a.y, b.y);
- out.z = Math.max(a.z, b.z);
- out.w = Math.max(a.w, b.w);
- return out;
-};
-
-/**
- * Math.round the components of a vec4
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a vector to round
- * @returns {vec4} out
- */
-vec4.round = function (out, a) {
- out.x = Math.round(a.x);
- out.y = Math.round(a.y);
- out.z = Math.round(a.z);
- out.w = Math.round(a.w);
- return out;
-};
-
-/**
- * Scales a vec4 by a scalar number
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the vector to scale
- * @param {Number} b amount to scale the vector by
- * @returns {vec4} out
- */
-vec4.scale = function (out, a, b) {
- out.x = a.x * b;
- out.y = a.y * b;
- out.z = a.z * b;
- out.w = a.w * b;
- return out;
-};
-
-/**
- * Adds two vec4's after scaling the second operand by a scalar value
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @param {Number} scale the amount to scale b by before adding
- * @returns {vec4} out
- */
-vec4.scaleAndAdd = function (out, a, b, scale) {
- out.x = a.x + (b.x * scale);
- out.y = a.y + (b.y * scale);
- out.z = a.z + (b.z * scale);
- out.w = a.w + (b.w * scale);
- return out;
-};
-
-/**
- * Calculates the euclidian distance between two vec4's
- *
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {Number} distance between a and b
- */
-vec4.distance = function (a, b) {
- var x = b.x - a.x,
- y = b.y - a.y,
- z = b.z - a.z,
- w = b.w - a.w;
- return Math.sqrt(x * x + y * y + z * z + w * w);
-};
-
-/**
- * Alias for {@link vec4.distance}
- * @function
- */
-vec4.dist = vec4.distance;
-
-/**
- * Calculates the squared euclidian distance between two vec4's
- *
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {Number} squared distance between a and b
- */
-vec4.squaredDistance = function (a, b) {
- var x = b.x - a.x,
- y = b.y - a.y,
- z = b.z - a.z,
- w = b.w - a.w;
- return x * x + y * y + z * z + w * w;
-};
-
-/**
- * Alias for {@link vec4.squaredDistance}
- * @function
- */
-vec4.sqrDist = vec4.squaredDistance;
-
-/**
- * Calculates the length of a vec4
- *
- * @param {vec4} a vector to calculate length of
- * @returns {Number} length of a
- */
-vec4.length = function (a) {
- var x = a.x,
- y = a.y,
- z = a.z,
- w = a.w;
- return Math.sqrt(x * x + y * y + z * z + w * w);
-};
-
-/**
- * Alias for {@link vec4.length}
- * @function
- */
-vec4.len = vec4.length;
-
-/**
- * Calculates the squared length of a vec4
- *
- * @param {vec4} a vector to calculate squared length of
- * @returns {Number} squared length of a
- */
-vec4.squaredLength = function (a) {
- var x = a.x,
- y = a.y,
- z = a.z,
- w = a.w;
- return x * x + y * y + z * z + w * w;
-};
-
-/**
- * Alias for {@link vec4.squaredLength}
- * @function
- */
-vec4.sqrLen = vec4.squaredLength;
-
-/**
- * Negates the components of a vec4
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a vector to negate
- * @returns {vec4} out
- */
-vec4.negate = function (out, a) {
- out.x = -a.x;
- out.y = -a.y;
- out.z = -a.z;
- out.w = -a.w;
- return out;
-};
-
-/**
- * Returns the inverse of the components of a vec4
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a vector to invert
- * @returns {vec4} out
- */
-vec4.inverse = function (out, a) {
- out.x = 1.0 / a.x;
- out.y = 1.0 / a.y;
- out.z = 1.0 / a.z;
- out.w = 1.0 / a.w;
- return out;
-};
-
-/**
- * Returns the inverse of the components of a vec4 safely
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a vector to invert
- * @returns {vec4} out
- */
-vec4.inverseSafe = function (out, a) {
- var x = a.x,
- y = a.y,
- z = a.z,
- w = a.w;
-
- if (Math.abs(x) < EPSILON) {
- out.x = 0;
- } else {
- out.x = 1.0 / x;
- }
-
- if (Math.abs(y) < EPSILON) {
- out.y = 0;
- } else {
- out.y = 1.0 / y;
- }
-
- if (Math.abs(z) < EPSILON) {
- out.z = 0;
- } else {
- out.z = 1.0 / z;
- }
-
- if (Math.abs(w) < EPSILON) {
- out.w = 0;
- } else {
- out.w = 1.0 / w;
- }
-
- return out;
-};
-
-/**
- * Normalize a vec4
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a vector to normalize
- * @returns {vec4} out
- */
-vec4.normalize = function (out, a) {
- var x = a.x,
- y = a.y,
- z = a.z,
- w = a.w;
- var len = x * x + y * y + z * z + w * w;
- if (len > 0) {
- len = 1 / Math.sqrt(len);
- out.x = x * len;
- out.y = y * len;
- out.z = z * len;
- out.w = w * len;
- }
- return out;
-};
-
-/**
- * Calculates the dot product of two vec4's
- *
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {Number} dot product of a and b
- */
-vec4.dot = function (a, b) {
- return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
-};
-
-/**
- * Performs a linear interpolation between two vec4's
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {vec4} out
- */
-vec4.lerp = function (out, a, b, t) {
- var ax = a.x,
- ay = a.y,
- az = a.z,
- aw = a.w;
- out.x = ax + t * (b.x - ax);
- out.y = ay + t * (b.y - ay);
- out.z = az + t * (b.z - az);
- out.w = aw + t * (b.w - aw);
- return out;
-};
-
-/**
- * Generates a random vector with the given scale
- *
- * @param {vec4} out the receiving vector
- * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
- * @returns {vec4} out
- */
-vec4.random = function (out, scale) {
- scale = scale || 1.0;
-
- //TODO: This is a pretty awful way of doing this. Find something better.
- out.x = random();
- out.y = random();
- out.z = random();
- out.w = random();
- vec4.normalize(out, out);
- vec4.scale(out, out, scale);
- return out;
-};
-
-/**
- * Transforms the vec4 with a mat4.
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the vector to transform
- * @param {mat4} m matrix to transform with
- * @returns {vec4} out
- */
-vec4.transformMat4 = function (out, a, m) {
- var x = a.x, y = a.y, z = a.z, w = a.w;
- out.x = m.m00 * x + m.m04 * y + m.m08 * z + m.m12 * w;
- out.y = m.m01 * x + m.m05 * y + m.m09 * z + m.m13 * w;
- out.z = m.m02 * x + m.m06 * y + m.m10 * z + m.m14 * w;
- out.w = m.m03 * x + m.m07 * y + m.m11 * z + m.m15 * w;
- return out;
-};
-
-/**
- * Transforms the vec4 with a quat
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the vector to transform
- * @param {quat} q quaternion to transform with
- * @returns {vec4} out
- */
-vec4.transformQuat = function (out, a, q) {
- var x = a.x, y = a.y, z = a.z;
- var qx = q.x, qy = q.y, qz = q.z, qw = q.w;
-
- // calculate quat * vec
- var ix = qw * x + qy * z - qz * y;
- var iy = qw * y + qz * x - qx * z;
- var iz = qw * z + qx * y - qy * x;
- var iw = -qx * x - qy * y - qz * z;
-
- // calculate result * inverse quat
- out.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
- out.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
- out.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
- out.w = a.w;
- return out;
-};
-
-/**
- * Perform some operation over an array of vec4s.
- *
- * @param {Array} a the array of vectors to iterate over
- * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
- * @param {Number} offset Number of elements to skip at the beginning of the array
- * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array
- * @param {Function} fn Function to call for each vector in the array
- * @param {Object} [arg] additional argument to pass to fn
- * @returns {Array} a
- * @function
- */
-vec4.forEach = (function () {
- var vec = vec4.create();
-
- return function (a, stride, offset, count, fn, arg) {
- var i, l;
- if (!stride) {
- stride = 4;
- }
-
- if (!offset) {
- offset = 0;
- }
-
- if (count) {
- l = Math.min((count * stride) + offset, a.length);
- } else {
- l = a.length;
- }
-
- for (i = offset; i < l; i += stride) {
- vec.x = a[i]; vec.y = a[i + 1]; vec.z = a[i + 2]; vec.w = a[i + 3];
- fn(vec, vec, arg);
- a[i] = vec.x; a[i + 1] = vec.y; a[i + 2] = vec.z; a[i + 3] = vec.w;
- }
-
- return a;
- };
-})();
-
-/**
- * Returns a string representation of a vector
- *
- * @param {vec4} a vector to represent as a string
- * @returns {String} string representation of the vector
- */
-vec4.str = function (a) {
- return ("vec4(" + (a.x) + ", " + (a.y) + ", " + (a.z) + ", " + (a.w) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {vec4} v
- * @returns {array}
- */
-vec4.array = function (out, v) {
- out[0] = v.x;
- out[1] = v.y;
- out[2] = v.z;
- out[3] = v.w;
-
- return out;
-};
-
-/**
- * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
- *
- * @param {vec4} a The first vector.
- * @param {vec4} b The second vector.
- * @returns {Boolean} True if the vectors are equal, false otherwise.
- */
-vec4.exactEquals = function (a, b) {
- return a.x === b.x && a.y === b.y && a.z === b.z && a.w === b.w;
-};
-
-/**
- * Returns whether or not the vectors have approximately the same elements in the same position.
- *
- * @param {vec4} a The first vector.
- * @param {vec4} b The second vector.
- * @returns {Boolean} True if the vectors are equal, false otherwise.
- */
-vec4.equals = function (a, b) {
- var a0 = a.x, a1 = a.y, a2 = a.z, a3 = a.w;
- var b0 = b.x, b1 = b.y, b2 = b.z, b3 = b.w;
- return (Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
- Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
- Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)));
-};
-
-var _tmp$3 = new Array(9);
-
-var _mat3 = function _mat3(m00, m01, m02, m03, m04, m05, m06, m07, m08) {
- this.m00 = m00;
- this.m01 = m01;
- this.m02 = m02;
- this.m03 = m03;
- this.m04 = m04;
- this.m05 = m05;
- this.m06 = m06;
- this.m07 = m07;
- this.m08 = m08;
-};
-
-_mat3.prototype.toJSON = function toJSON () {
- _tmp$3[0] = this.m00;
- _tmp$3[1] = this.m01;
- _tmp$3[2] = this.m02;
- _tmp$3[3] = this.m03;
- _tmp$3[4] = this.m04;
- _tmp$3[5] = this.m05;
- _tmp$3[6] = this.m06;
- _tmp$3[7] = this.m07;
- _tmp$3[8] = this.m08;
-
- return _tmp$3;
-};
-
-/**
- * @class 3x3 Matrix
- * @name mat3
- *
- * NOTE: we use column-major matrix for all matrix calculation.
- *
- * This may lead to some confusion when referencing OpenGL documentation,
- * however, which represents out all matricies in column-major format.
- * This means that while in code a matrix may be typed out as:
- *
- * [1, 0, 0, 0,
- * 0, 1, 0, 0,
- * 0, 0, 1, 0,
- * x, y, z, 0]
- *
- * The same matrix in the [OpenGL documentation](https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTranslate.xml)
- * is written as:
- *
- * 1 0 0 x
- * 0 1 0 y
- * 0 0 1 z
- * 0 0 0 0
- *
- * Please rest assured, however, that they are the same thing!
- * This is not unique to glMatrix, either, as OpenGL developers have long been confused by the
- * apparent lack of consistency between the memory layout and the documentation.
- */
-var mat3 = {};
-
-/**
- * Creates a new identity mat3
- *
- * @returns {mat3} a new 3x3 matrix
- */
-mat3.create = function () {
- return new _mat3(
- 1, 0, 0,
- 0, 1, 0,
- 0, 0, 1
- );
-};
-
-/**
- * Create a new mat3 with the given values
- *
- * @param {Number} m00 Component in column 0, row 0 position (index 0)
- * @param {Number} m01 Component in column 0, row 1 position (index 1)
- * @param {Number} m02 Component in column 0, row 2 position (index 2)
- * @param {Number} m10 Component in column 1, row 0 position (index 3)
- * @param {Number} m11 Component in column 1, row 1 position (index 4)
- * @param {Number} m12 Component in column 1, row 2 position (index 5)
- * @param {Number} m20 Component in column 2, row 0 position (index 6)
- * @param {Number} m21 Component in column 2, row 1 position (index 7)
- * @param {Number} m22 Component in column 2, row 2 position (index 8)
- * @returns {mat3} A new mat3
- */
-mat3.new = function (m00, m01, m02, m10, m11, m12, m20, m21, m22) {
- return new _mat3(
- m00, m01, m02,
- m10, m11, m12,
- m20, m21, m22
- );
-};
-
-/**
- * Creates a new mat3 initialized with values from an existing matrix
- *
- * @param {mat3} a matrix to clone
- * @returns {mat3} a new 3x3 matrix
- */
-mat3.clone = function (a) {
- return new _mat3(
- a.m00, a.m01, a.m02,
- a.m03, a.m04, a.m05,
- a.m06, a.m07, a.m08
- );
-};
-
-/**
- * Copy the values from one mat3 to another
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the source matrix
- * @returns {mat3} out
- */
-mat3.copy = function (out, a) {
- out.m00 = a.m00;
- out.m01 = a.m01;
- out.m02 = a.m02;
- out.m03 = a.m03;
- out.m04 = a.m04;
- out.m05 = a.m05;
- out.m06 = a.m06;
- out.m07 = a.m07;
- out.m08 = a.m08;
- return out;
-};
-
-/**
- * Set the components of a mat3 to the given values
- *
- * @param {mat3} out the receiving matrix
- * @param {Number} m00 Component in column 0, row 0 position (index 0)
- * @param {Number} m01 Component in column 0, row 1 position (index 1)
- * @param {Number} m02 Component in column 0, row 2 position (index 2)
- * @param {Number} m10 Component in column 1, row 0 position (index 3)
- * @param {Number} m11 Component in column 1, row 1 position (index 4)
- * @param {Number} m12 Component in column 1, row 2 position (index 5)
- * @param {Number} m20 Component in column 2, row 0 position (index 6)
- * @param {Number} m21 Component in column 2, row 1 position (index 7)
- * @param {Number} m22 Component in column 2, row 2 position (index 8)
- * @returns {mat3} out
- */
-mat3.set = function (out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {
- out.m00 = m00;
- out.m01 = m01;
- out.m02 = m02;
- out.m03 = m10;
- out.m04 = m11;
- out.m05 = m12;
- out.m06 = m20;
- out.m07 = m21;
- out.m08 = m22;
- return out;
-};
-
-/**
- * Set a mat3 to the identity matrix
- *
- * @param {mat3} out the receiving matrix
- * @returns {mat3} out
- */
-mat3.identity = function (out) {
- out.m00 = 1;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 1;
- out.m05 = 0;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 1;
- return out;
-};
-
-/**
- * Transpose the values of a mat3
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the source matrix
- * @returns {mat3} out
- */
-mat3.transpose = function (out, a) {
- // If we are transposing ourselves we can skip a few steps but have to cache some values
- if (out === a) {
- var a01 = a.m01, a02 = a.m02, a12 = a.m05;
- out.m01 = a.m03;
- out.m02 = a.m06;
- out.m03 = a01;
- out.m05 = a.m07;
- out.m06 = a02;
- out.m07 = a12;
- } else {
- out.m00 = a.m00;
- out.m01 = a.m03;
- out.m02 = a.m06;
- out.m03 = a.m01;
- out.m04 = a.m04;
- out.m05 = a.m07;
- out.m06 = a.m02;
- out.m07 = a.m05;
- out.m08 = a.m08;
- }
-
- return out;
-};
-
-/**
- * Inverts a mat3
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the source matrix
- * @returns {mat3} out
- */
-mat3.invert = function (out, a) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02,
- a10 = a.m03, a11 = a.m04, a12 = a.m05,
- a20 = a.m06, a21 = a.m07, a22 = a.m08;
-
- var b01 = a22 * a11 - a12 * a21;
- var b11 = -a22 * a10 + a12 * a20;
- var b21 = a21 * a10 - a11 * a20;
-
- // Calculate the determinant
- var det = a00 * b01 + a01 * b11 + a02 * b21;
-
- if (!det) {
- return null;
- }
- det = 1.0 / det;
-
- out.m00 = b01 * det;
- out.m01 = (-a22 * a01 + a02 * a21) * det;
- out.m02 = (a12 * a01 - a02 * a11) * det;
- out.m03 = b11 * det;
- out.m04 = (a22 * a00 - a02 * a20) * det;
- out.m05 = (-a12 * a00 + a02 * a10) * det;
- out.m06 = b21 * det;
- out.m07 = (-a21 * a00 + a01 * a20) * det;
- out.m08 = (a11 * a00 - a01 * a10) * det;
- return out;
-};
-
-/**
- * Calculates the adjugate of a mat3
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the source matrix
- * @returns {mat3} out
- */
-mat3.adjoint = function (out, a) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02,
- a10 = a.m03, a11 = a.m04, a12 = a.m05,
- a20 = a.m06, a21 = a.m07, a22 = a.m08;
-
- out.m00 = (a11 * a22 - a12 * a21);
- out.m01 = (a02 * a21 - a01 * a22);
- out.m02 = (a01 * a12 - a02 * a11);
- out.m03 = (a12 * a20 - a10 * a22);
- out.m04 = (a00 * a22 - a02 * a20);
- out.m05 = (a02 * a10 - a00 * a12);
- out.m06 = (a10 * a21 - a11 * a20);
- out.m07 = (a01 * a20 - a00 * a21);
- out.m08 = (a00 * a11 - a01 * a10);
- return out;
-};
-
-/**
- * Calculates the determinant of a mat3
- *
- * @param {mat3} a the source matrix
- * @returns {Number} determinant of a
- */
-mat3.determinant = function (a) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02,
- a10 = a.m03, a11 = a.m04, a12 = a.m05,
- a20 = a.m06, a21 = a.m07, a22 = a.m08;
-
- return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
-};
-
-/**
- * Multiplies two mat3's
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the first operand
- * @param {mat3} b the second operand
- * @returns {mat3} out
- */
-mat3.multiply = function (out, a, b) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02,
- a10 = a.m03, a11 = a.m04, a12 = a.m05,
- a20 = a.m06, a21 = a.m07, a22 = a.m08;
-
- var b00 = b.m00, b01 = b.m01, b02 = b.m02;
- var b10 = b.m03, b11 = b.m04, b12 = b.m05;
- var b20 = b.m06, b21 = b.m07, b22 = b.m08;
-
- out.m00 = b00 * a00 + b01 * a10 + b02 * a20;
- out.m01 = b00 * a01 + b01 * a11 + b02 * a21;
- out.m02 = b00 * a02 + b01 * a12 + b02 * a22;
-
- out.m03 = b10 * a00 + b11 * a10 + b12 * a20;
- out.m04 = b10 * a01 + b11 * a11 + b12 * a21;
- out.m05 = b10 * a02 + b11 * a12 + b12 * a22;
-
- out.m06 = b20 * a00 + b21 * a10 + b22 * a20;
- out.m07 = b20 * a01 + b21 * a11 + b22 * a21;
- out.m08 = b20 * a02 + b21 * a12 + b22 * a22;
- return out;
-};
-
-/**
- * Alias for {@link mat3.multiply}
- * @function
- */
-mat3.mul = mat3.multiply;
-
-/**
- * Translate a mat3 by the given vector
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the matrix to translate
- * @param {vec2} v vector to translate by
- * @returns {mat3} out
- */
-mat3.translate = function (out, a, v) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02,
- a10 = a.m03, a11 = a.m04, a12 = a.m05,
- a20 = a.m06, a21 = a.m07, a22 = a.m08;
- var x = v.x, y = v.y;
-
- out.m00 = a00;
- out.m01 = a01;
- out.m02 = a02;
-
- out.m03 = a10;
- out.m04 = a11;
- out.m05 = a12;
-
- out.m06 = x * a00 + y * a10 + a20;
- out.m07 = x * a01 + y * a11 + a21;
- out.m08 = x * a02 + y * a12 + a22;
- return out;
-};
-
-/**
- * Rotates a mat3 by the given angle
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat3} out
- */
-mat3.rotate = function (out, a, rad) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02,
- a10 = a.m03, a11 = a.m04, a12 = a.m05,
- a20 = a.m06, a21 = a.m07, a22 = a.m08;
-
- var s = Math.sin(rad);
- var c = Math.cos(rad);
-
- out.m00 = c * a00 + s * a10;
- out.m01 = c * a01 + s * a11;
- out.m02 = c * a02 + s * a12;
-
- out.m03 = c * a10 - s * a00;
- out.m04 = c * a11 - s * a01;
- out.m05 = c * a12 - s * a02;
-
- out.m06 = a20;
- out.m07 = a21;
- out.m08 = a22;
- return out;
-};
-
-/**
- * Scales the mat3 by the dimensions in the given vec2
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the matrix to rotate
- * @param {vec2} v the vec2 to scale the matrix by
- * @returns {mat3} out
- **/
-mat3.scale = function (out, a, v) {
- var x = v.x, y = v.y;
-
- out.m00 = x * a.m00;
- out.m01 = x * a.m01;
- out.m02 = x * a.m02;
-
- out.m03 = y * a.m03;
- out.m04 = y * a.m04;
- out.m05 = y * a.m05;
-
- out.m06 = a.m06;
- out.m07 = a.m07;
- out.m08 = a.m08;
- return out;
-};
-
-/**
- * Copies the upper-left 3x3 values into the given mat3.
- *
- * @param {mat3} out the receiving 3x3 matrix
- * @param {mat4} a the source 4x4 matrix
- * @returns {mat3} out
- */
-mat3.fromMat4 = function (out, a) {
- out.m00 = a.m00;
- out.m01 = a.m01;
- out.m02 = a.m02;
- out.m03 = a.m04;
- out.m04 = a.m05;
- out.m05 = a.m06;
- out.m06 = a.m08;
- out.m07 = a.m09;
- out.m08 = a.m10;
- return out;
-};
-
-/**
- * Creates a matrix from a vector translation
- * This is equivalent to (but much faster than):
- *
- * mat3.identity(dest);
- * mat3.translate(dest, dest, vec);
- *
- * @param {mat3} out mat3 receiving operation result
- * @param {vec2} v Translation vector
- * @returns {mat3} out
- */
-mat3.fromTranslation = function (out, v) {
- out.m00 = 1;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 1;
- out.m05 = 0;
- out.m06 = v.x;
- out.m07 = v.y;
- out.m08 = 1;
- return out;
-};
-
-/**
- * Creates a matrix from a given angle
- * This is equivalent to (but much faster than):
- *
- * mat3.identity(dest);
- * mat3.rotate(dest, dest, rad);
- *
- * @param {mat3} out mat3 receiving operation result
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat3} out
- */
-mat3.fromRotation = function (out, rad) {
- var s = Math.sin(rad), c = Math.cos(rad);
-
- out.m00 = c;
- out.m01 = s;
- out.m02 = 0;
-
- out.m03 = -s;
- out.m04 = c;
- out.m05 = 0;
-
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 1;
- return out;
-};
-
-/**
- * Creates a matrix from a vector scaling
- * This is equivalent to (but much faster than):
- *
- * mat3.identity(dest);
- * mat3.scale(dest, dest, vec);
- *
- * @param {mat3} out mat3 receiving operation result
- * @param {vec2} v Scaling vector
- * @returns {mat3} out
- */
-mat3.fromScaling = function (out, v) {
- out.m00 = v.x;
- out.m01 = 0;
- out.m02 = 0;
-
- out.m03 = 0;
- out.m04 = v.y;
- out.m05 = 0;
-
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 1;
- return out;
-};
-
-/**
- * Copies the values from a mat2d into a mat3
- *
- * @param {mat3} out the receiving matrix
- * @param {mat2d} a the matrix to copy
- * @returns {mat3} out
- **/
-mat3.fromMat2d = function (out, a) {
- out.m00 = a.m00;
- out.m01 = a.m01;
- out.m02 = 0;
-
- out.m03 = a.m02;
- out.m04 = a.m03;
- out.m05 = 0;
-
- out.m06 = a.m04;
- out.m07 = a.m05;
- out.m08 = 1;
- return out;
-};
-
-/**
-* Calculates a 3x3 matrix from the given quaternion
-*
-* @param {mat3} out mat3 receiving operation result
-* @param {quat} q Quaternion to create matrix from
-*
-* @returns {mat3} out
-*/
-mat3.fromQuat = function (out, q) {
- var x = q.x, y = q.y, z = q.z, w = q.w;
- var x2 = x + x;
- var y2 = y + y;
- var z2 = z + z;
-
- var xx = x * x2;
- var yx = y * x2;
- var yy = y * y2;
- var zx = z * x2;
- var zy = z * y2;
- var zz = z * z2;
- var wx = w * x2;
- var wy = w * y2;
- var wz = w * z2;
-
- out.m00 = 1 - yy - zz;
- out.m03 = yx - wz;
- out.m06 = zx + wy;
-
- out.m01 = yx + wz;
- out.m04 = 1 - xx - zz;
- out.m07 = zy - wx;
-
- out.m02 = zx - wy;
- out.m05 = zy + wx;
- out.m08 = 1 - xx - yy;
-
- return out;
-};
-
-/**
-* Calculates a 3x3 matrix from view direction and up direction
-*
-* @param {mat3} out mat3 receiving operation result
-* @param {vec3} view view direction (must be normalized)
-* @param {vec3} [up] up direction, default is (0,1,0) (must be normalized)
-*
-* @returns {mat3} out
-*/
-mat3.fromViewUp = (function () {
- var default_up = vec3.new(0, 1, 0);
- var x = vec3.create();
- var y = vec3.create();
-
- return function (out, view, up) {
- if (vec3.sqrLen(view) < EPSILON * EPSILON) {
- mat3.identity(out);
- return out;
- }
-
- up = up || default_up;
- vec3.cross(x, up, view);
-
- if (vec3.sqrLen(x) < EPSILON * EPSILON) {
- mat3.identity(out);
- return out;
- }
-
- vec3.cross(y, view, x);
- mat3.set(out,
- x.x, x.y, x.z,
- y.x, y.y, y.z,
- view.x, view.y, view.z
- );
-
- return out;
- };
-})();
-
-/**
-* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
-*
-* @param {mat3} out mat3 receiving operation result
-* @param {mat4} a Mat4 to derive the normal matrix from
-*
-* @returns {mat3} out
-*/
-mat3.normalFromMat4 = function (out, a) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02, a03 = a.m03,
- a10 = a.m04, a11 = a.m05, a12 = a.m06, a13 = a.m07,
- a20 = a.m08, a21 = a.m09, a22 = a.m10, a23 = a.m11,
- a30 = a.m12, a31 = a.m13, a32 = a.m14, a33 = a.m15;
-
- var b00 = a00 * a11 - a01 * a10;
- var b01 = a00 * a12 - a02 * a10;
- var b02 = a00 * a13 - a03 * a10;
- var b03 = a01 * a12 - a02 * a11;
- var b04 = a01 * a13 - a03 * a11;
- var b05 = a02 * a13 - a03 * a12;
- var b06 = a20 * a31 - a21 * a30;
- var b07 = a20 * a32 - a22 * a30;
- var b08 = a20 * a33 - a23 * a30;
- var b09 = a21 * a32 - a22 * a31;
- var b10 = a21 * a33 - a23 * a31;
- var b11 = a22 * a33 - a23 * a32;
-
- // Calculate the determinant
- var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
-
- if (!det) {
- return null;
- }
- det = 1.0 / det;
-
- out.m00 = (a11 * b11 - a12 * b10 + a13 * b09) * det;
- out.m01 = (a12 * b08 - a10 * b11 - a13 * b07) * det;
- out.m02 = (a10 * b10 - a11 * b08 + a13 * b06) * det;
-
- out.m03 = (a02 * b10 - a01 * b11 - a03 * b09) * det;
- out.m04 = (a00 * b11 - a02 * b08 + a03 * b07) * det;
- out.m05 = (a01 * b08 - a00 * b10 - a03 * b06) * det;
-
- out.m06 = (a31 * b05 - a32 * b04 + a33 * b03) * det;
- out.m07 = (a32 * b02 - a30 * b05 - a33 * b01) * det;
- out.m08 = (a30 * b04 - a31 * b02 + a33 * b00) * det;
-
- return out;
-};
-
-/**
- * Returns a string representation of a mat3
- *
- * @param {mat3} a matrix to represent as a string
- * @returns {String} string representation of the matrix
- */
-mat3.str = function (a) {
- return ("mat3(" + (a.m00) + ", " + (a.m01) + ", " + (a.m02) + ", " + (a.m03) + ", " + (a.m04) + ", " + (a.m05) + ", " + (a.m06) + ", " + (a.m07) + ", " + (a.m08) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {mat3} m
- * @returns {array}
- */
-mat3.array = function (out, m) {
- out[0] = m.m00;
- out[1] = m.m01;
- out[2] = m.m02;
- out[3] = m.m03;
- out[4] = m.m04;
- out[5] = m.m05;
- out[6] = m.m06;
- out[7] = m.m07;
- out[8] = m.m08;
-
- return out;
-};
-
-/**
- * Returns Frobenius norm of a mat3
- *
- * @param {mat3} a the matrix to calculate Frobenius norm of
- * @returns {Number} Frobenius norm
- */
-mat3.frob = function (a) {
- return (Math.sqrt(Math.pow(a.m00, 2) + Math.pow(a.m01, 2) + Math.pow(a.m02, 2) + Math.pow(a.m03, 2) + Math.pow(a.m04, 2) + Math.pow(a.m05, 2) + Math.pow(a.m06, 2) + Math.pow(a.m07, 2) + Math.pow(a.m08, 2)));
-};
-
-/**
- * Adds two mat3's
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the first operand
- * @param {mat3} b the second operand
- * @returns {mat3} out
- */
-mat3.add = function (out, a, b) {
- out.m00 = a.m00 + b.m00;
- out.m01 = a.m01 + b.m01;
- out.m02 = a.m02 + b.m02;
- out.m03 = a.m03 + b.m03;
- out.m04 = a.m04 + b.m04;
- out.m05 = a.m05 + b.m05;
- out.m06 = a.m06 + b.m06;
- out.m07 = a.m07 + b.m07;
- out.m08 = a.m08 + b.m08;
- return out;
-};
-
-/**
- * Subtracts matrix b from matrix a
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the first operand
- * @param {mat3} b the second operand
- * @returns {mat3} out
- */
-mat3.subtract = function (out, a, b) {
- out.m00 = a.m00 - b.m00;
- out.m01 = a.m01 - b.m01;
- out.m02 = a.m02 - b.m02;
- out.m03 = a.m03 - b.m03;
- out.m04 = a.m04 - b.m04;
- out.m05 = a.m05 - b.m05;
- out.m06 = a.m06 - b.m06;
- out.m07 = a.m07 - b.m07;
- out.m08 = a.m08 - b.m08;
- return out;
-};
-
-/**
- * Alias for {@link mat3.subtract}
- * @function
- */
-mat3.sub = mat3.subtract;
-
-/**
- * Multiply each element of the matrix by a scalar.
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the matrix to scale
- * @param {Number} b amount to scale the matrix's elements by
- * @returns {mat3} out
- */
-mat3.multiplyScalar = function (out, a, b) {
- out.m00 = a.m00 * b;
- out.m01 = a.m01 * b;
- out.m02 = a.m02 * b;
- out.m03 = a.m03 * b;
- out.m04 = a.m04 * b;
- out.m05 = a.m05 * b;
- out.m06 = a.m06 * b;
- out.m07 = a.m07 * b;
- out.m08 = a.m08 * b;
- return out;
-};
-
-/**
- * Adds two mat3's after multiplying each element of the second operand by a scalar value.
- *
- * @param {mat3} out the receiving vector
- * @param {mat3} a the first operand
- * @param {mat3} b the second operand
- * @param {Number} scale the amount to scale b's elements by before adding
- * @returns {mat3} out
- */
-mat3.multiplyScalarAndAdd = function (out, a, b, scale) {
- out.m00 = a.m00 + (b.m00 * scale);
- out.m01 = a.m01 + (b.m01 * scale);
- out.m02 = a.m02 + (b.m02 * scale);
- out.m03 = a.m03 + (b.m03 * scale);
- out.m04 = a.m04 + (b.m04 * scale);
- out.m05 = a.m05 + (b.m05 * scale);
- out.m06 = a.m06 + (b.m06 * scale);
- out.m07 = a.m07 + (b.m07 * scale);
- out.m08 = a.m08 + (b.m08 * scale);
- return out;
-};
-
-/**
- * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
- *
- * @param {mat3} a The first matrix.
- * @param {mat3} b The second matrix.
- * @returns {Boolean} True if the matrices are equal, false otherwise.
- */
-mat3.exactEquals = function (a, b) {
- return a.m00 === b.m00 && a.m01 === b.m01 && a.m02 === b.m02 &&
- a.m03 === b.m03 && a.m04 === b.m04 && a.m05 === b.m05 &&
- a.m06 === b.m06 && a.m07 === b.m07 && a.m08 === b.m08;
-};
-
-/**
- * Returns whether or not the matrices have approximately the same elements in the same position.
- *
- * @param {mat3} a The first matrix.
- * @param {mat3} b The second matrix.
- * @returns {Boolean} True if the matrices are equal, false otherwise.
- */
-mat3.equals = function (a, b) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03, a4 = a.m04, a5 = a.m05, a6 = a.m06, a7 = a.m07, a8 = a.m08;
- var b0 = b.m00, b1 = b.m01, b2 = b.m02, b3 = b.m03, b4 = b.m04, b5 = b.m05, b6 = b.m06, b7 = b.m07, b8 = b.m08;
- return (
- Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
- Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
- Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&
- Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&
- Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&
- Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&
- Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) &&
- Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8))
- );
-};
-
-var _tmp$4 = new Array(4);
-
-var _quat = function _quat(x, y, z, w) {
- this.x = x;
- this.y = y;
- this.z = z;
- this.w = w;
-};
-
-_quat.prototype.toJSON = function toJSON () {
- _tmp$4[0] = this.x;
- _tmp$4[1] = this.y;
- _tmp$4[2] = this.z;
- _tmp$4[3] = this.w;
-
- return _tmp$4;
-};
-
-/**
- * @class Quaternion
- * @name quat
- */
-var quat = {};
-
-/**
- * Creates a new identity quat
- *
- * @returns {quat} a new quaternion
- */
-quat.create = function () {
- return new _quat(0, 0, 0, 1);
-};
-
-/**
- * Creates a new quat initialized with the given values
- *
- * @param {Number} x X component
- * @param {Number} y Y component
- * @param {Number} z Z component
- * @param {Number} w W component
- * @returns {quat} a new quaternion
- * @function
- */
-quat.new = function (x, y, z, w) {
- return new _quat(x, y, z, w);
-};
-
-/**
- * Creates a new quat initialized with values from an existing quaternion
- *
- * @param {quat} a quaternion to clone
- * @returns {quat} a new quaternion
- * @function
- */
-quat.clone = function (a) {
- return new _quat(a.x, a.y, a.z, a.w);
-};
-
-/**
- * Copy the values from one quat to another
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a the source quaternion
- * @returns {quat} out
- * @function
- */
-quat.copy = vec4.copy;
-
-/**
- * Set the components of a quat to the given values
- *
- * @param {quat} out the receiving quaternion
- * @param {Number} x X component
- * @param {Number} y Y component
- * @param {Number} z Z component
- * @param {Number} w W component
- * @returns {quat} out
- * @function
- */
-quat.set = vec4.set;
-
-/**
- * Set a quat to the identity quaternion
- *
- * @param {quat} out the receiving quaternion
- * @returns {quat} out
- */
-quat.identity = function (out) {
- out.x = 0;
- out.y = 0;
- out.z = 0;
- out.w = 1;
- return out;
-};
-
-/**
- * Sets a quaternion to represent the shortest rotation from one
- * vector to another.
- *
- * Both vectors are assumed to be unit length.
- *
- * @param {quat} out the receiving quaternion.
- * @param {vec3} a the initial vector
- * @param {vec3} b the destination vector
- * @returns {quat} out
- */
-quat.rotationTo = (function () {
- var tmpvec3 = vec3.create();
- var xUnitVec3 = vec3.new(1, 0, 0);
- var yUnitVec3 = vec3.new(0, 1, 0);
-
- return function (out, a, b) {
- var dot = vec3.dot(a, b);
- if (dot < -0.999999) {
- vec3.cross(tmpvec3, xUnitVec3, a);
- if (vec3.length(tmpvec3) < 0.000001) {
- vec3.cross(tmpvec3, yUnitVec3, a);
- }
- vec3.normalize(tmpvec3, tmpvec3);
- quat.fromAxisAngle(out, tmpvec3, Math.PI);
- return out;
- } else if (dot > 0.999999) {
- out.x = 0;
- out.y = 0;
- out.z = 0;
- out.w = 1;
- return out;
- } else {
- vec3.cross(tmpvec3, a, b);
- out.x = tmpvec3.x;
- out.y = tmpvec3.y;
- out.z = tmpvec3.z;
- out.w = 1 + dot;
- return quat.normalize(out, out);
- }
- };
-})();
-
-/**
- * Gets the rotation axis and angle for a given
- * quaternion. If a quaternion is created with
- * fromAxisAngle, this method will return the same
- * values as providied in the original parameter list
- * OR functionally equivalent values.
- * Example: The quaternion formed by axis [0, 0, 1] and
- * angle -90 is the same as the quaternion formed by
- * [0, 0, 1] and 270. This method favors the latter.
- * @param {vec3} out_axis Vector receiving the axis of rotation
- * @param {quat} q Quaternion to be decomposed
- * @return {Number} Angle, in radians, of the rotation
- */
-quat.getAxisAngle = function (out_axis, q) {
- var rad = Math.acos(q.w) * 2.0;
- var s = Math.sin(rad / 2.0);
- if (s != 0.0) {
- out_axis.x = q.x / s;
- out_axis.y = q.y / s;
- out_axis.z = q.z / s;
- } else {
- // If s is zero, return any axis (no rotation - axis does not matter)
- out_axis.x = 1;
- out_axis.y = 0;
- out_axis.z = 0;
- }
- return rad;
-};
-
-/**
- * Multiplies two quat's
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a the first operand
- * @param {quat} b the second operand
- * @returns {quat} out
- */
-quat.multiply = function (out, a, b) {
- var ax = a.x, ay = a.y, az = a.z, aw = a.w,
- bx = b.x, by = b.y, bz = b.z, bw = b.w;
-
- out.x = ax * bw + aw * bx + ay * bz - az * by;
- out.y = ay * bw + aw * by + az * bx - ax * bz;
- out.z = az * bw + aw * bz + ax * by - ay * bx;
- out.w = aw * bw - ax * bx - ay * by - az * bz;
- return out;
-};
-
-/**
- * Alias for {@link quat.multiply}
- * @function
- */
-quat.mul = quat.multiply;
-
-/**
- * Scales a quat by a scalar number
- *
- * @param {quat} out the receiving vector
- * @param {quat} a the vector to scale
- * @param {Number} b amount to scale the vector by
- * @returns {quat} out
- * @function
- */
-quat.scale = vec4.scale;
-
-/**
- * Rotates a quaternion by the given angle about the X axis
- *
- * @param {quat} out quat receiving operation result
- * @param {quat} a quat to rotate
- * @param {number} rad angle (in radians) to rotate
- * @returns {quat} out
- */
-quat.rotateX = function (out, a, rad) {
- rad *= 0.5;
-
- var ax = a.x, ay = a.y, az = a.z, aw = a.w,
- bx = Math.sin(rad), bw = Math.cos(rad);
-
- out.x = ax * bw + aw * bx;
- out.y = ay * bw + az * bx;
- out.z = az * bw - ay * bx;
- out.w = aw * bw - ax * bx;
- return out;
-};
-
-/**
- * Rotates a quaternion by the given angle about the Y axis
- *
- * @param {quat} out quat receiving operation result
- * @param {quat} a quat to rotate
- * @param {number} rad angle (in radians) to rotate
- * @returns {quat} out
- */
-quat.rotateY = function (out, a, rad) {
- rad *= 0.5;
-
- var ax = a.x, ay = a.y, az = a.z, aw = a.w,
- by = Math.sin(rad), bw = Math.cos(rad);
-
- out.x = ax * bw - az * by;
- out.y = ay * bw + aw * by;
- out.z = az * bw + ax * by;
- out.w = aw * bw - ay * by;
- return out;
-};
-
-/**
- * Rotates a quaternion by the given angle about the Z axis
- *
- * @param {quat} out quat receiving operation result
- * @param {quat} a quat to rotate
- * @param {number} rad angle (in radians) to rotate
- * @returns {quat} out
- */
-quat.rotateZ = function (out, a, rad) {
- rad *= 0.5;
-
- var ax = a.x, ay = a.y, az = a.z, aw = a.w,
- bz = Math.sin(rad), bw = Math.cos(rad);
-
- out.x = ax * bw + ay * bz;
- out.y = ay * bw - ax * bz;
- out.z = az * bw + aw * bz;
- out.w = aw * bw - az * bz;
- return out;
-};
-
-/**
- * Rotates a quaternion by the given angle about the axis in world space
- *
- * @param {quat} out quat receiving operation result
- * @param {quat} rot quat to rotate
- * @param {vec3} axis the axis around which to rotate in world space
- * @param {number} rad angle (in radians) to rotate
- * @returns {quat} out
- */
-quat.rotateAround = (function () {
- var v3_tmp = vec3.create();
- var q_tmp = quat.create();
-
- return function (out, rot, axis, rad) {
- // get inv-axis (local to rot)
- quat.invert(q_tmp, rot);
- vec3.transformQuat(v3_tmp, axis, q_tmp);
- // rotate by inv-axis
- quat.fromAxisAngle(q_tmp, v3_tmp, rad);
- quat.mul(out, rot, q_tmp);
-
- return out;
- };
-})();
-
-/**
- * Rotates a quaternion by the given angle about the axis in local space
- *
- * @param {quat} out quat receiving operation result
- * @param {quat} rot quat to rotate
- * @param {vec3} axis the axis around which to rotate in local space
- * @param {number} rad angle (in radians) to rotate
- * @returns {quat} out
- */
-quat.rotateAroundLocal = (function () {
- var q_tmp = quat.create();
-
- return function (out, rot, axis, rad) {
- quat.fromAxisAngle(q_tmp, axis, rad);
- quat.mul(out, rot, q_tmp);
-
- return out;
- };
-})();
-
-/**
- * Calculates the W component of a quat from the X, Y, and Z components.
- * Assumes that quaternion is 1 unit in length.
- * Any existing W component will be ignored.
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a quat to calculate W component of
- * @returns {quat} out
- */
-quat.calculateW = function (out, a) {
- var x = a.x, y = a.y, z = a.z;
-
- out.x = x;
- out.y = y;
- out.z = z;
- out.w = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
- return out;
-};
-
-/**
- * Calculates the dot product of two quat's
- *
- * @param {quat} a the first operand
- * @param {quat} b the second operand
- * @returns {Number} dot product of a and b
- * @function
- */
-quat.dot = vec4.dot;
-
-/**
- * Performs a linear interpolation between two quat's
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a the first operand
- * @param {quat} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {quat} out
- * @function
- */
-quat.lerp = vec4.lerp;
-
-/**
- * Performs a spherical linear interpolation between two quat
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a the first operand
- * @param {quat} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {quat} out
- */
-quat.slerp = function (out, a, b, t) {
- // benchmarks:
- // http://jsperf.com/quaternion-slerp-implementations
-
- var ax = a.x, ay = a.y, az = a.z, aw = a.w,
- bx = b.x, by = b.y, bz = b.z, bw = b.w;
-
- var omega, cosom, sinom, scale0, scale1;
-
- // calc cosine
- cosom = ax * bx + ay * by + az * bz + aw * bw;
- // adjust signs (if necessary)
- if (cosom < 0.0) {
- cosom = -cosom;
- bx = - bx;
- by = - by;
- bz = - bz;
- bw = - bw;
- }
- // calculate coefficients
- if ((1.0 - cosom) > 0.000001) {
- // standard case (slerp)
- omega = Math.acos(cosom);
- sinom = Math.sin(omega);
- scale0 = Math.sin((1.0 - t) * omega) / sinom;
- scale1 = Math.sin(t * omega) / sinom;
- } else {
- // "from" and "to" quaternions are very close
- // ... so we can do a linear interpolation
- scale0 = 1.0 - t;
- scale1 = t;
- }
- // calculate final values
- out.x = scale0 * ax + scale1 * bx;
- out.y = scale0 * ay + scale1 * by;
- out.z = scale0 * az + scale1 * bz;
- out.w = scale0 * aw + scale1 * bw;
-
- return out;
-};
-
-/**
- * Performs a spherical linear interpolation with two control points
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a the first operand
- * @param {quat} b the second operand
- * @param {quat} c the third operand
- * @param {quat} d the fourth operand
- * @param {Number} t interpolation amount
- * @returns {quat} out
- */
-quat.sqlerp = (function () {
- var temp1 = quat.create();
- var temp2 = quat.create();
-
- return function (out, a, b, c, d, t) {
- quat.slerp(temp1, a, d, t);
- quat.slerp(temp2, b, c, t);
- quat.slerp(out, temp1, temp2, 2 * t * (1 - t));
-
- return out;
- };
-}());
-
-/**
- * Calculates the inverse of a quat
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a quat to calculate inverse of
- * @returns {quat} out
- */
-quat.invert = function (out, a) {
- var a0 = a.x, a1 = a.y, a2 = a.z, a3 = a.w;
- var dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
- var invDot = dot ? 1.0 / dot : 0;
-
- // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
-
- out.x = -a0 * invDot;
- out.y = -a1 * invDot;
- out.z = -a2 * invDot;
- out.w = a3 * invDot;
- return out;
-};
-
-/**
- * Calculates the conjugate of a quat
- * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a quat to calculate conjugate of
- * @returns {quat} out
- */
-quat.conjugate = function (out, a) {
- out.x = -a.x;
- out.y = -a.y;
- out.z = -a.z;
- out.w = a.w;
- return out;
-};
-
-/**
- * Calculates the length of a quat
- *
- * @param {quat} a vector to calculate length of
- * @returns {Number} length of a
- * @function
- */
-quat.length = vec4.length;
-
-/**
- * Alias for {@link quat.length}
- * @function
- */
-quat.len = quat.length;
-
-/**
- * Calculates the squared length of a quat
- *
- * @param {quat} a vector to calculate squared length of
- * @returns {Number} squared length of a
- * @function
- */
-quat.squaredLength = vec4.squaredLength;
-
-/**
- * Alias for {@link quat.squaredLength}
- * @function
- */
-quat.sqrLen = quat.squaredLength;
-
-/**
- * Normalize a quat
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a quaternion to normalize
- * @returns {quat} out
- * @function
- */
-quat.normalize = vec4.normalize;
-
-/**
- * Sets the specified quaternion with values corresponding to the given
- * axes. Each axis is a vec3 and is expected to be unit length and
- * perpendicular to all other specified axes.
- *
- * @param {vec3} xAxis the vector representing the local "right" direction
- * @param {vec3} yAxis the vector representing the local "up" direction
- * @param {vec3} zAxis the vector representing the viewing direction
- * @returns {quat} out
- */
-quat.fromAxes = (function () {
- var matr = mat3.create();
-
- return function (out, xAxis, yAxis, zAxis) {
- mat3.set(
- matr,
- xAxis.x, xAxis.y, xAxis.z,
- yAxis.x, yAxis.y, yAxis.z,
- zAxis.x, zAxis.y, zAxis.z
- );
- return quat.normalize(out, quat.fromMat3(out, matr));
- };
-})();
-
-/**
-* Calculates a quaternion from view direction and up direction
-*
-* @param {quat} out mat3 receiving operation result
-* @param {vec3} view view direction (must be normalized)
-* @param {vec3} [up] up direction, default is (0,1,0) (must be normalized)
-*
-* @returns {quat} out
-*/
-quat.fromViewUp = (function () {
- var matr = mat3.create();
-
- return function (out, view, up) {
- mat3.fromViewUp(matr, view, up);
- if (!matr) {
- return null;
- }
-
- return quat.normalize(out, quat.fromMat3(out, matr));
- };
-})();
-
-/**
- * Sets a quat from the given angle and rotation axis,
- * then returns it.
- *
- * @param {quat} out the receiving quaternion
- * @param {vec3} axis the axis around which to rotate
- * @param {Number} rad the angle in radians
- * @returns {quat} out
- **/
-quat.fromAxisAngle = function (out, axis, rad) {
- rad = rad * 0.5;
- var s = Math.sin(rad);
- out.x = s * axis.x;
- out.y = s * axis.y;
- out.z = s * axis.z;
- out.w = Math.cos(rad);
- return out;
-};
-
-/**
- * Creates a quaternion from the given 3x3 rotation matrix.
- *
- * NOTE: The resultant quaternion is not normalized, so you should be sure
- * to renormalize the quaternion yourself where necessary.
- *
- * @param {quat} out the receiving quaternion
- * @param {mat3} m rotation matrix
- * @returns {quat} out
- * @function
- */
-quat.fromMat3 = function (out, m) {
- // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
-
- var m00 = m.m00, m01 = m.m03, m02 = m.m06,
- m10 = m.m01, m11 = m.m04, m12 = m.m07,
- m20 = m.m02, m21 = m.m05, m22 = m.m08;
-
- var trace = m00 + m11 + m22;
-
- if (trace > 0) {
- var s = 0.5 / Math.sqrt(trace + 1.0);
-
- out.w = 0.25 / s;
- out.x = (m21 - m12) * s;
- out.y = (m02 - m20) * s;
- out.z = (m10 - m01) * s;
-
- } else if ((m00 > m11) && (m00 > m22)) {
- var s$1 = 2.0 * Math.sqrt(1.0 + m00 - m11 - m22);
-
- out.w = (m21 - m12) / s$1;
- out.x = 0.25 * s$1;
- out.y = (m01 + m10) / s$1;
- out.z = (m02 + m20) / s$1;
-
- } else if (m11 > m22) {
- var s$2 = 2.0 * Math.sqrt(1.0 + m11 - m00 - m22);
-
- out.w = (m02 - m20) / s$2;
- out.x = (m01 + m10) / s$2;
- out.y = 0.25 * s$2;
- out.z = (m12 + m21) / s$2;
-
- } else {
- var s$3 = 2.0 * Math.sqrt(1.0 + m22 - m00 - m11);
-
- out.w = (m10 - m01) / s$3;
- out.x = (m02 + m20) / s$3;
- out.y = (m12 + m21) / s$3;
- out.z = 0.25 * s$3;
- }
-
- return out;
-};
-
-/**
- * Creates a quaternion from the given euler angle x, y, z.
- *
- * @param {quat} out the receiving quaternion
- * @param {x} Angle to rotate around X axis in degrees.
- * @param {y} Angle to rotate around Y axis in degrees.
- * @param {z} Angle to rotate around Z axis in degrees.
- * @returns {quat} out
- * @function
- */
-quat.fromEuler = function (out, x, y, z) {
- var halfToRad = 0.5 * Math.PI / 180.0;
- x *= halfToRad;
- y *= halfToRad;
- z *= halfToRad;
-
- var sx = Math.sin(x);
- var cx = Math.cos(x);
- var sy = Math.sin(y);
- var cy = Math.cos(y);
- var sz = Math.sin(z);
- var cz = Math.cos(z);
-
- out.x = sx * cy * cz - cx * sy * sz;
- out.y = cx * sy * cz + sx * cy * sz;
- out.z = cx * cy * sz - sx * sy * cz;
- out.w = cx * cy * cz + sx * sy * sz;
-
- return out;
-};
-
-/**
- * Returns a string representation of a quatenion
- *
- * @param {quat} a vector to represent as a string
- * @returns {String} string representation of the vector
- */
-quat.str = function (a) {
- return ("quat(" + (a.x) + ", " + (a.y) + ", " + (a.z) + ", " + (a.w) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {quat} q
- * @returns {array}
- */
-quat.array = function (out, q) {
- out[0] = q.x;
- out[1] = q.y;
- out[2] = q.z;
- out[3] = q.w;
-
- return out;
-};
-
-/**
- * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)
- *
- * @param {quat} a The first quaternion.
- * @param {quat} b The second quaternion.
- * @returns {Boolean} True if the vectors are equal, false otherwise.
- */
-quat.exactEquals = vec4.exactEquals;
-
-/**
- * Returns whether or not the quaternions have approximately the same elements in the same position.
- *
- * @param {quat} a The first vector.
- * @param {quat} b The second vector.
- * @returns {Boolean} True if the vectors are equal, false otherwise.
- */
-quat.equals = vec4.equals;
-
-var _tmp$5 = new Array(4);
-
-var _mat2 = function _mat2(m00, m01, m02, m03) {
- this.m00 = m00;
- this.m01 = m01;
- this.m02 = m02;
- this.m03 = m03;
-};
-
-_mat2.prototype.toJSON = function toJSON () {
- _tmp$5[0] = this.m00;
- _tmp$5[1] = this.m01;
- _tmp$5[2] = this.m02;
- _tmp$5[3] = this.m03;
-
- return _tmp$5;
-};
-
-/**
- * @class 2x2 Matrix
- * @name mat2
- */
-var mat2 = {};
-
-/**
- * Creates a new identity mat2
- *
- * @returns {mat2} a new 2x2 matrix
- */
-mat2.create = function() {
- return new _mat2(1, 0, 0, 1);
-};
-
-/**
- * Create a new mat2 with the given values
- *
- * @param {Number} m00 Component in column 0, row 0 position (index 0)
- * @param {Number} m01 Component in column 0, row 1 position (index 1)
- * @param {Number} m10 Component in column 1, row 0 position (index 2)
- * @param {Number} m11 Component in column 1, row 1 position (index 3)
- * @returns {mat2} out A new 2x2 matrix
- */
-mat2.new = function (m00, m01, m10, m11) {
- return new _mat2(m00, m01, m10, m11);
-};
-
-/**
- * Creates a new mat2 initialized with values from an existing matrix
- *
- * @param {mat2} a matrix to clone
- * @returns {mat2} a new 2x2 matrix
- */
-mat2.clone = function (a) {
- return new _mat2(a.m00, a.m01, a.m02, a.m03);
-};
-
-/**
- * Copy the values from one mat2 to another
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the source matrix
- * @returns {mat2} out
- */
-mat2.copy = function (out, a) {
- out.m00 = a.m00;
- out.m01 = a.m01;
- out.m02 = a.m02;
- out.m03 = a.m03;
- return out;
-};
-
-/**
- * Set a mat2 to the identity matrix
- *
- * @param {mat2} out the receiving matrix
- * @returns {mat2} out
- */
-mat2.identity = function (out) {
- out.m00 = 1;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 1;
- return out;
-};
-
-/**
- * Set the components of a mat2 to the given values
- *
- * @param {mat2} out the receiving matrix
- * @param {Number} m00 Component in column 0, row 0 position (index 0)
- * @param {Number} m01 Component in column 0, row 1 position (index 1)
- * @param {Number} m10 Component in column 1, row 0 position (index 2)
- * @param {Number} m11 Component in column 1, row 1 position (index 3)
- * @returns {mat2} out
- */
-mat2.set = function (out, m00, m01, m10, m11) {
- out.m00 = m00;
- out.m01 = m01;
- out.m02 = m10;
- out.m03 = m11;
- return out;
-};
-
-
-/**
- * Transpose the values of a mat2
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the source matrix
- * @returns {mat2} out
- */
-mat2.transpose = function (out, a) {
- // If we are transposing ourselves we can skip a few steps but have to cache some values
- if (out === a) {
- var a1 = a.m01;
- out.m01 = a.m02;
- out.m02 = a1;
- } else {
- out.m00 = a.m00;
- out.m01 = a.m02;
- out.m02 = a.m01;
- out.m03 = a.m03;
- }
-
- return out;
-};
-
-/**
- * Inverts a mat2
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the source matrix
- * @returns {mat2} out
- */
-mat2.invert = function (out, a) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03;
-
- // Calculate the determinant
- var det = a0 * a3 - a2 * a1;
-
- if (!det) {
- return null;
- }
- det = 1.0 / det;
-
- out.m00 = a3 * det;
- out.m01 = -a1 * det;
- out.m02 = -a2 * det;
- out.m03 = a0 * det;
-
- return out;
-};
-
-/**
- * Calculates the adjugate of a mat2
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the source matrix
- * @returns {mat2} out
- */
-mat2.adjoint = function (out, a) {
- // Caching this value is nessecary if out == a
- var a0 = a.m00;
- out.m00 = a.m03;
- out.m01 = -a.m01;
- out.m02 = -a.m02;
- out.m03 = a0;
-
- return out;
-};
-
-/**
- * Calculates the determinant of a mat2
- *
- * @param {mat2} a the source matrix
- * @returns {Number} determinant of a
- */
-mat2.determinant = function (a) {
- return a.m00 * a.m03 - a.m02 * a.m01;
-};
-
-/**
- * Multiplies two mat2's
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the first operand
- * @param {mat2} b the second operand
- * @returns {mat2} out
- */
-mat2.multiply = function (out, a, b) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03;
- var b0 = b.m00, b1 = b.m01, b2 = b.m02, b3 = b.m03;
- out.m00 = a0 * b0 + a2 * b1;
- out.m01 = a1 * b0 + a3 * b1;
- out.m02 = a0 * b2 + a2 * b3;
- out.m03 = a1 * b2 + a3 * b3;
- return out;
-};
-
-/**
- * Alias for {@link mat2.multiply}
- * @function
- */
-mat2.mul = mat2.multiply;
-
-/**
- * Rotates a mat2 by the given angle
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat2} out
- */
-mat2.rotate = function (out, a, rad) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03,
- s = Math.sin(rad),
- c = Math.cos(rad);
- out.m00 = a0 * c + a2 * s;
- out.m01 = a1 * c + a3 * s;
- out.m02 = a0 * -s + a2 * c;
- out.m03 = a1 * -s + a3 * c;
- return out;
-};
-
-/**
- * Scales the mat2 by the dimensions in the given vec2
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the matrix to rotate
- * @param {vec2} v the vec2 to scale the matrix by
- * @returns {mat2} out
- **/
-mat2.scale = function (out, a, v) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03,
- v0 = v.x, v1 = v.y;
- out.m00 = a0 * v0;
- out.m01 = a1 * v0;
- out.m02 = a2 * v1;
- out.m03 = a3 * v1;
- return out;
-};
-
-/**
- * Creates a matrix from a given angle
- * This is equivalent to (but much faster than):
- *
- * mat2.identity(dest);
- * mat2.rotate(dest, dest, rad);
- *
- * @param {mat2} out mat2 receiving operation result
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat2} out
- */
-mat2.fromRotation = function (out, rad) {
- var s = Math.sin(rad),
- c = Math.cos(rad);
- out.m00 = c;
- out.m01 = s;
- out.m02 = -s;
- out.m03 = c;
- return out;
-};
-
-/**
- * Creates a matrix from a vector scaling
- * This is equivalent to (but much faster than):
- *
- * mat2.identity(dest);
- * mat2.scale(dest, dest, vec);
- *
- * @param {mat2} out mat2 receiving operation result
- * @param {vec2} v Scaling vector
- * @returns {mat2} out
- */
-mat2.fromScaling = function (out, v) {
- out.m00 = v.x;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = v.y;
- return out;
-};
-
-/**
- * Returns a string representation of a mat2
- *
- * @param {mat2} a matrix to represent as a string
- * @returns {String} string representation of the matrix
- */
-mat2.str = function (a) {
- return ("mat2(" + (a.m00) + ", " + (a.m01) + ", " + (a.m02) + ", " + (a.m03) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {mat2} m
- * @returns {array}
- */
-mat2.array = function (out, m) {
- out[0] = m.m00;
- out[1] = m.m01;
- out[2] = m.m02;
- out[3] = m.m03;
-
- return out;
-};
-
-/**
- * Returns Frobenius norm of a mat2
- *
- * @param {mat2} a the matrix to calculate Frobenius norm of
- * @returns {Number} Frobenius norm
- */
-mat2.frob = function (a) {
- return (Math.sqrt(Math.pow(a.m00, 2) + Math.pow(a.m01, 2) + Math.pow(a.m02, 2) + Math.pow(a.m03, 2)));
-};
-
-/**
- * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
- * @param {mat2} L the lower triangular matrix
- * @param {mat2} D the diagonal matrix
- * @param {mat2} U the upper triangular matrix
- * @param {mat2} a the input matrix to factorize
- */
-
-mat2.LDU = function (L, D, U, a) {
- L.m02 = a.m02 / a.m00;
- U.m00 = a.m00;
- U.m01 = a.m01;
- U.m03 = a.m03 - L.m02 * U.m01;
-};
-
-/**
- * Adds two mat2's
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the first operand
- * @param {mat2} b the second operand
- * @returns {mat2} out
- */
-mat2.add = function (out, a, b) {
- out.m00 = a.m00 + b.m00;
- out.m01 = a.m01 + b.m01;
- out.m02 = a.m02 + b.m02;
- out.m03 = a.m03 + b.m03;
- return out;
-};
-
-/**
- * Subtracts matrix b from matrix a
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the first operand
- * @param {mat2} b the second operand
- * @returns {mat2} out
- */
-mat2.subtract = function (out, a, b) {
- out.m00 = a.m00 - b.m00;
- out.m01 = a.m01 - b.m01;
- out.m02 = a.m02 - b.m02;
- out.m03 = a.m03 - b.m03;
- return out;
-};
-
-/**
- * Alias for {@link mat2.subtract}
- * @function
- */
-mat2.sub = mat2.subtract;
-
-/**
- * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
- *
- * @param {mat2} a The first matrix.
- * @param {mat2} b The second matrix.
- * @returns {Boolean} True if the matrices are equal, false otherwise.
- */
-mat2.exactEquals = function (a, b) {
- return a.m00 === b.m00 && a.m01 === b.m01 && a.m02 === b.m02 && a.m03 === b.m03;
-};
-
-/**
- * Returns whether or not the matrices have approximately the same elements in the same position.
- *
- * @param {mat2} a The first matrix.
- * @param {mat2} b The second matrix.
- * @returns {Boolean} True if the matrices are equal, false otherwise.
- */
-mat2.equals = function (a, b) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03;
- var b0 = b.m00, b1 = b.m01, b2 = b.m02, b3 = b.m03;
- return (
- Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
- Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
- Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3))
- );
-};
-
-/**
- * Multiply each element of the matrix by a scalar.
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the matrix to scale
- * @param {Number} b amount to scale the matrix's elements by
- * @returns {mat2} out
- */
-mat2.multiplyScalar = function (out, a, b) {
- out.m00 = a.m00 * b;
- out.m01 = a.m01 * b;
- out.m02 = a.m02 * b;
- out.m03 = a.m03 * b;
- return out;
-};
-
-/**
- * Adds two mat2's after multiplying each element of the second operand by a scalar value.
- *
- * @param {mat2} out the receiving vector
- * @param {mat2} a the first operand
- * @param {mat2} b the second operand
- * @param {Number} scale the amount to scale b's elements by before adding
- * @returns {mat2} out
- */
-mat2.multiplyScalarAndAdd = function (out, a, b, scale) {
- out.m00 = a.m00 + (b.m00 * scale);
- out.m01 = a.m01 + (b.m01 * scale);
- out.m02 = a.m02 + (b.m02 * scale);
- out.m03 = a.m03 + (b.m03 * scale);
- return out;
-};
-
-var _tmp$6 = new Array(6);
-
-var _mat23 = function _mat23(m00, m01, m02, m03, m04, m05) {
- this.m00 = m00;
- this.m01 = m01;
- this.m02 = m02;
- this.m03 = m03;
- this.m04 = m04;
- this.m05 = m05;
-};
-
-_mat23.prototype.toJSON = function toJSON () {
- _tmp$6[0] = this.m00;
- _tmp$6[1] = this.m01;
- _tmp$6[2] = this.m02;
- _tmp$6[3] = this.m03;
- _tmp$6[4] = this.m04;
- _tmp$6[5] = this.m05;
-
- return _tmp$6;
-};
-
-/**
- * @class 2x3 Matrix
- * @name mat23
- *
- * @description
- * A mat23 contains six elements defined as:
- *
- * [a, c, tx,
- * b, d, ty]
- *
- * This is a short form for the 3x3 matrix:
- *
- * [a, c, tx,
- * b, d, ty,
- * 0, 0, 1]
- *
- * The last row is ignored so the array is shorter and operations are faster.
- */
-var mat23 = {};
-
-/**
- * Creates a new identity mat23
- *
- * @returns {mat23} a new 2x3 matrix
- */
-mat23.create = function () {
- return new _mat23(
- 1, 0,
- 0, 1,
- 0, 0
- );
-};
-
-/**
- * Create a new mat23 with the given values
- *
- * @param {Number} a Component A (index 0)
- * @param {Number} b Component B (index 1)
- * @param {Number} c Component C (index 2)
- * @param {Number} d Component D (index 3)
- * @param {Number} tx Component TX (index 4)
- * @param {Number} ty Component TY (index 5)
- * @returns {mat23} A new mat23
- */
-mat23.new = function (a, b, c, d, tx, ty) {
- return new _mat23(
- a, b,
- c, d,
- tx, ty
- );
-};
-
-/**
- * Creates a new mat23 initialized with values from an existing matrix
- *
- * @param {mat23} a matrix to clone
- * @returns {mat23} a new 2x3 matrix
- */
-mat23.clone = function (a) {
- return new _mat23(
- a.m00, a.m01,
- a.m02, a.m03,
- a.m04, a.m05
- );
-};
-
-/**
- * Copy the values from one mat23 to another
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the source matrix
- * @returns {mat23} out
- */
-mat23.copy = function (out, a) {
- out.m00 = a.m00;
- out.m01 = a.m01;
- out.m02 = a.m02;
- out.m03 = a.m03;
- out.m04 = a.m04;
- out.m05 = a.m05;
- return out;
-};
-
-/**
- * Set a mat23 to the identity matrix
- *
- * @param {mat23} out the receiving matrix
- * @returns {mat23} out
- */
-mat23.identity = function (out) {
- out.m00 = 1;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 1;
- out.m04 = 0;
- out.m05 = 0;
- return out;
-};
-
-/**
- * Set the components of a mat23 to the given values
- *
- * @param {mat23} out the receiving matrix
- * @param {Number} a Component A (index 0)
- * @param {Number} b Component B (index 1)
- * @param {Number} c Component C (index 2)
- * @param {Number} d Component D (index 3)
- * @param {Number} tx Component TX (index 4)
- * @param {Number} ty Component TY (index 5)
- * @returns {mat23} out
- */
-mat23.set = function (out, a, b, c, d, tx, ty) {
- out.m00 = a;
- out.m01 = b;
- out.m02 = c;
- out.m03 = d;
- out.m04 = tx;
- out.m05 = ty;
- return out;
-};
-
-/**
- * Inverts a mat23
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the source matrix
- * @returns {mat23} out
- */
-mat23.invert = function (out, a) {
- var aa = a.m00, ab = a.m01, ac = a.m02, ad = a.m03,
- atx = a.m04, aty = a.m05;
-
- var det = aa * ad - ab * ac;
- if (!det) {
- return null;
- }
- det = 1.0 / det;
-
- out.m00 = ad * det;
- out.m01 = -ab * det;
- out.m02 = -ac * det;
- out.m03 = aa * det;
- out.m04 = (ac * aty - ad * atx) * det;
- out.m05 = (ab * atx - aa * aty) * det;
- return out;
-};
-
-/**
- * Calculates the determinant of a mat23
- *
- * @param {mat23} a the source matrix
- * @returns {Number} determinant of a
- */
-mat23.determinant = function (a) {
- return a.m00 * a.m03 - a.m01 * a.m02;
-};
-
-/**
- * Multiplies two mat23's
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the first operand
- * @param {mat23} b the second operand
- * @returns {mat23} out
- */
-mat23.multiply = function (out, a, b) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03, a4 = a.m04, a5 = a.m05,
- b0 = b.m00, b1 = b.m01, b2 = b.m02, b3 = b.m03, b4 = b.m04, b5 = b.m05;
- out.m00 = a0 * b0 + a2 * b1;
- out.m01 = a1 * b0 + a3 * b1;
- out.m02 = a0 * b2 + a2 * b3;
- out.m03 = a1 * b2 + a3 * b3;
- out.m04 = a0 * b4 + a2 * b5 + a4;
- out.m05 = a1 * b4 + a3 * b5 + a5;
- return out;
-};
-
-/**
- * Alias for {@link mat23.multiply}
- * @function
- */
-mat23.mul = mat23.multiply;
-
-/**
- * Rotates a mat23 by the given angle
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat23} out
- */
-mat23.rotate = function (out, a, rad) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03, a4 = a.m04, a5 = a.m05,
- s = Math.sin(rad),
- c = Math.cos(rad);
- out.m00 = a0 * c + a2 * s;
- out.m01 = a1 * c + a3 * s;
- out.m02 = a0 * -s + a2 * c;
- out.m03 = a1 * -s + a3 * c;
- out.m04 = a4;
- out.m05 = a5;
- return out;
-};
-
-/**
- * Scales the mat23 by the dimensions in the given vec2
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the matrix to translate
- * @param {vec2} v the vec2 to scale the matrix by
- * @returns {mat23} out
- **/
-mat23.scale = function (out, a, v) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03, a4 = a.m04, a5 = a.m05,
- v0 = v.x, v1 = v.y;
- out.m00 = a0 * v0;
- out.m01 = a1 * v0;
- out.m02 = a2 * v1;
- out.m03 = a3 * v1;
- out.m04 = a4;
- out.m05 = a5;
- return out;
-};
-
-/**
- * Translates the mat23 by the dimensions in the given vec2
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the matrix to translate
- * @param {vec2} v the vec2 to translate the matrix by
- * @returns {mat23} out
- **/
-mat23.translate = function (out, a, v) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03, a4 = a.m04, a5 = a.m05,
- v0 = v.x, v1 = v.y;
- out.m00 = a0;
- out.m01 = a1;
- out.m02 = a2;
- out.m03 = a3;
- out.m04 = a0 * v0 + a2 * v1 + a4;
- out.m05 = a1 * v0 + a3 * v1 + a5;
- return out;
-};
-
-/**
- * Creates a matrix from a given angle
- * This is equivalent to (but much faster than):
- *
- * mat23.identity(dest);
- * mat23.rotate(dest, dest, rad);
- *
- * @param {mat23} out mat23 receiving operation result
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat23} out
- */
-mat23.fromRotation = function (out, rad) {
- var s = Math.sin(rad), c = Math.cos(rad);
- out.m00 = c;
- out.m01 = s;
- out.m02 = -s;
- out.m03 = c;
- out.m04 = 0;
- out.m05 = 0;
- return out;
-};
-
-/**
- * Creates a matrix from a vector scaling
- * This is equivalent to (but much faster than):
- *
- * mat23.identity(dest);
- * mat23.scale(dest, dest, vec);
- *
- * @param {mat23} out mat23 receiving operation result
- * @param {vec2} v Scaling vector
- * @returns {mat23} out
- */
-mat23.fromScaling = function (out, v) {
- out.m00 = v.m00;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = v.m01;
- out.m04 = 0;
- out.m05 = 0;
- return out;
-};
-
-/**
- * Creates a matrix from a vector translation
- * This is equivalent to (but much faster than):
- *
- * mat23.identity(dest);
- * mat23.translate(dest, dest, vec);
- *
- * @param {mat23} out mat23 receiving operation result
- * @param {vec2} v Translation vector
- * @returns {mat23} out
- */
-mat23.fromTranslation = function (out, v) {
- out.m00 = 1;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 1;
- out.m04 = v.x;
- out.m05 = v.y;
- return out;
-};
-
-/**
- * Returns a string representation of a mat23
- *
- * @param {mat23} a matrix to represent as a string
- * @returns {String} string representation of the matrix
- */
-mat23.str = function (a) {
- return ("mat23(" + (a.m00) + ", " + (a.m01) + ", " + (a.m02) + ", " + (a.m03) + ", " + (a.m04) + ", " + (a.m05) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {mat23} m
- * @returns {array}
- */
-mat23.array = function (out, m) {
- out[0] = m.m00;
- out[1] = m.m01;
- out[2] = m.m02;
- out[3] = m.m03;
- out[4] = m.m04;
- out[5] = m.m05;
-
- return out;
-};
-
-/**
- * Returns typed array to 16 float array
- *
- * @param {array} out
- * @param {mat23} m
- * @returns {array}
- */
-mat23.array4x4 = function (out, m) {
- out[0] = m.m00;
- out[1] = m.m01;
- out[2] = 0;
- out[3] = 0;
- out[4] = m.m02;
- out[5] = m.m03;
- out[6] = 0;
- out[7] = 0;
- out[8] = 0;
- out[9] = 0;
- out[10] = 1;
- out[11] = 0;
- out[12] = m.m04;
- out[13] = m.m05;
- out[14] = 0;
- out[15] = 1;
-
- return out;
-};
-
-/**
- * Returns Frobenius norm of a mat23
- *
- * @param {mat23} a the matrix to calculate Frobenius norm of
- * @returns {Number} Frobenius norm
- */
-mat23.frob = function (a) {
- return (Math.sqrt(Math.pow(a.m00, 2) + Math.pow(a.m01, 2) + Math.pow(a.m02, 2) + Math.pow(a.m03, 2) + Math.pow(a.m04, 2) + Math.pow(a.m05, 2) + 1));
-};
-
-/**
- * Adds two mat23's
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the first operand
- * @param {mat23} b the second operand
- * @returns {mat23} out
- */
-mat23.add = function (out, a, b) {
- out.m00 = a.m00 + b.m00;
- out.m01 = a.m01 + b.m01;
- out.m02 = a.m02 + b.m02;
- out.m03 = a.m03 + b.m03;
- out.m04 = a.m04 + b.m04;
- out.m05 = a.m05 + b.m05;
- return out;
-};
-
-/**
- * Subtracts matrix b from matrix a
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the first operand
- * @param {mat23} b the second operand
- * @returns {mat23} out
- */
-mat23.subtract = function (out, a, b) {
- out.m00 = a.m00 - b.m00;
- out.m01 = a.m01 - b.m01;
- out.m02 = a.m02 - b.m02;
- out.m03 = a.m03 - b.m03;
- out.m04 = a.m04 - b.m04;
- out.m05 = a.m05 - b.m05;
- return out;
-};
-
-/**
- * Alias for {@link mat23.subtract}
- * @function
- */
-mat23.sub = mat23.subtract;
-
-/**
- * Multiply each element of the matrix by a scalar.
- *
- * @param {mat23} out the receiving matrix
- * @param {mat23} a the matrix to scale
- * @param {Number} b amount to scale the matrix's elements by
- * @returns {mat23} out
- */
-mat23.multiplyScalar = function (out, a, b) {
- out.m00 = a.m00 * b;
- out.m01 = a.m01 * b;
- out.m02 = a.m02 * b;
- out.m03 = a.m03 * b;
- out.m04 = a.m04 * b;
- out.m05 = a.m05 * b;
- return out;
-};
-
-/**
- * Adds two mat23's after multiplying each element of the second operand by a scalar value.
- *
- * @param {mat23} out the receiving vector
- * @param {mat23} a the first operand
- * @param {mat23} b the second operand
- * @param {Number} scale the amount to scale b's elements by before adding
- * @returns {mat23} out
- */
-mat23.multiplyScalarAndAdd = function (out, a, b, scale) {
- out.m00 = a.m00 + (b.m00 * scale);
- out.m01 = a.m01 + (b.m01 * scale);
- out.m02 = a.m02 + (b.m02 * scale);
- out.m03 = a.m03 + (b.m03 * scale);
- out.m04 = a.m04 + (b.m04 * scale);
- out.m05 = a.m05 + (b.m05 * scale);
- return out;
-};
-
-/**
- * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
- *
- * @param {mat23} a The first matrix.
- * @param {mat23} b The second matrix.
- * @returns {Boolean} True if the matrices are equal, false otherwise.
- */
-mat23.exactEquals = function (a, b) {
- return a.m00 === b.m00 && a.m01 === b.m01 && a.m02 === b.m02 && a.m03 === b.m03 && a.m04 === b.m04 && a.m05 === b.m05;
-};
-
-/**
- * Returns whether or not the matrices have approximately the same elements in the same position.
- *
- * @param {mat23} a The first matrix.
- * @param {mat23} b The second matrix.
- * @returns {Boolean} True if the matrices are equal, false otherwise.
- */
-mat23.equals = function (a, b) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03, a4 = a.m04, a5 = a.m05;
- var b0 = b.m00, b1 = b.m01, b2 = b.m02, b3 = b.m03, b4 = b.m04, b5 = b.m05;
- return (
- Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
- Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
- Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&
- Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&
- Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5))
- );
-};
-
-var _tmp$7 = new Array(16);
-
-var _mat4 = function _mat4(
- m00, m01, m02, m03,
- m04, m05, m06, m07,
- m08, m09, m10, m11,
- m12, m13, m14, m15
-) {
- this.m00 = m00;
- this.m01 = m01;
- this.m02 = m02;
- this.m03 = m03;
- this.m04 = m04;
- this.m05 = m05;
- this.m06 = m06;
- this.m07 = m07;
- this.m08 = m08;
- this.m09 = m09;
- this.m10 = m10;
- this.m11 = m11;
- this.m12 = m12;
- this.m13 = m13;
- this.m14 = m14;
- this.m15 = m15;
-};
-
-_mat4.prototype.toJSON = function toJSON () {
- _tmp$7[0] = this.m00;
- _tmp$7[1] = this.m01;
- _tmp$7[2] = this.m02;
- _tmp$7[3] = this.m03;
- _tmp$7[4] = this.m04;
- _tmp$7[5] = this.m05;
- _tmp$7[6] = this.m06;
- _tmp$7[7] = this.m07;
- _tmp$7[8] = this.m08;
- _tmp$7[9] = this.m09;
- _tmp$7[10] = this.m10;
- _tmp$7[11] = this.m11;
- _tmp$7[12] = this.m12;
- _tmp$7[13] = this.m13;
- _tmp$7[14] = this.m14;
- _tmp$7[15] = this.m15;
-
- return _tmp$7;
-};
-
-/**
- * @class 4x4 Matrix
- * @name mat4
- *
- * NOTE: we use column-major matrix for all matrix calculation.
- *
- * This may lead to some confusion when referencing OpenGL documentation,
- * however, which represents out all matricies in column-major format.
- * This means that while in code a matrix may be typed out as:
- *
- * [1, 0, 0, 0,
- * 0, 1, 0, 0,
- * 0, 0, 1, 0,
- * x, y, z, 0]
- *
- * The same matrix in the [OpenGL documentation](https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTranslate.xml)
- * is written as:
- *
- * 1 0 0 x
- * 0 1 0 y
- * 0 0 1 z
- * 0 0 0 0
- *
- * Please rest assured, however, that they are the same thing!
- * This is not unique to glMatrix, either, as OpenGL developers have long been confused by the
- * apparent lack of consistency between the memory layout and the documentation.
- */
-var mat4 = {};
-
-/**
- * Creates a new identity mat4
- *
- * @returns {mat4} a new 4x4 matrix
- */
-mat4.create = function () {
- return new _mat4(
- 1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1
- );
-};
-
-/**
- * Create a new mat4 with the given values
- *
- * @param {Number} m00 Component in column 0, row 0 position (index 0)
- * @param {Number} m01 Component in column 0, row 1 position (index 1)
- * @param {Number} m02 Component in column 0, row 2 position (index 2)
- * @param {Number} m03 Component in column 0, row 3 position (index 3)
- * @param {Number} m10 Component in column 1, row 0 position (index 4)
- * @param {Number} m11 Component in column 1, row 1 position (index 5)
- * @param {Number} m12 Component in column 1, row 2 position (index 6)
- * @param {Number} m13 Component in column 1, row 3 position (index 7)
- * @param {Number} m20 Component in column 2, row 0 position (index 8)
- * @param {Number} m21 Component in column 2, row 1 position (index 9)
- * @param {Number} m22 Component in column 2, row 2 position (index 10)
- * @param {Number} m23 Component in column 2, row 3 position (index 11)
- * @param {Number} m30 Component in column 3, row 0 position (index 12)
- * @param {Number} m31 Component in column 3, row 1 position (index 13)
- * @param {Number} m32 Component in column 3, row 2 position (index 14)
- * @param {Number} m33 Component in column 3, row 3 position (index 15)
- * @returns {mat4} A new mat4
- */
-mat4.new = function (m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
- return new _mat4(
- m00, m01, m02, m03,
- m10, m11, m12, m13,
- m20, m21, m22, m23,
- m30, m31, m32, m33
- );
-};
-
-/**
- * Creates a new mat4 initialized with values from an existing matrix
- *
- * @param {mat4} a matrix to clone
- * @returns {mat4} a new 4x4 matrix
- */
-mat4.clone = function (a) {
- return new _mat4(
- a.m00, a.m01, a.m02, a.m03,
- a.m04, a.m05, a.m06, a.m07,
- a.m08, a.m09, a.m10, a.m11,
- a.m12, a.m13, a.m14, a.m15
- );
-};
-
-/**
- * Copy the values from one mat4 to another
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the source matrix
- * @returns {mat4} out
- */
-mat4.copy = function (out, a) {
- out.m00 = a.m00;
- out.m01 = a.m01;
- out.m02 = a.m02;
- out.m03 = a.m03;
- out.m04 = a.m04;
- out.m05 = a.m05;
- out.m06 = a.m06;
- out.m07 = a.m07;
- out.m08 = a.m08;
- out.m09 = a.m09;
- out.m10 = a.m10;
- out.m11 = a.m11;
- out.m12 = a.m12;
- out.m13 = a.m13;
- out.m14 = a.m14;
- out.m15 = a.m15;
- return out;
-};
-
-/**
- * Set the components of a mat4 to the given values
- *
- * @param {mat4} out the receiving matrix
- * @param {Number} m00 Component in column 0, row 0 position (index 0)
- * @param {Number} m01 Component in column 0, row 1 position (index 1)
- * @param {Number} m02 Component in column 0, row 2 position (index 2)
- * @param {Number} m03 Component in column 0, row 3 position (index 3)
- * @param {Number} m10 Component in column 1, row 0 position (index 4)
- * @param {Number} m11 Component in column 1, row 1 position (index 5)
- * @param {Number} m12 Component in column 1, row 2 position (index 6)
- * @param {Number} m13 Component in column 1, row 3 position (index 7)
- * @param {Number} m20 Component in column 2, row 0 position (index 8)
- * @param {Number} m21 Component in column 2, row 1 position (index 9)
- * @param {Number} m22 Component in column 2, row 2 position (index 10)
- * @param {Number} m23 Component in column 2, row 3 position (index 11)
- * @param {Number} m30 Component in column 3, row 0 position (index 12)
- * @param {Number} m31 Component in column 3, row 1 position (index 13)
- * @param {Number} m32 Component in column 3, row 2 position (index 14)
- * @param {Number} m33 Component in column 3, row 3 position (index 15)
- * @returns {mat4} out
- */
-mat4.set = function (out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
- out.m00 = m00;
- out.m01 = m01;
- out.m02 = m02;
- out.m03 = m03;
- out.m04 = m10;
- out.m05 = m11;
- out.m06 = m12;
- out.m07 = m13;
- out.m08 = m20;
- out.m09 = m21;
- out.m10 = m22;
- out.m11 = m23;
- out.m12 = m30;
- out.m13 = m31;
- out.m14 = m32;
- out.m15 = m33;
- return out;
-};
-
-
-/**
- * Set a mat4 to the identity matrix
- *
- * @param {mat4} out the receiving matrix
- * @returns {mat4} out
- */
-mat4.identity = function (out) {
- out.m00 = 1;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 0;
- out.m05 = 1;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 0;
- out.m09 = 0;
- out.m10 = 1;
- out.m11 = 0;
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = 0;
- out.m15 = 1;
- return out;
-};
-
-/**
- * Transpose the values of a mat4
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the source matrix
- * @returns {mat4} out
- */
-mat4.transpose = function (out, a) {
- // If we are transposing ourselves we can skip a few steps but have to cache some values
- if (out === a) {
- var a01 = a.m01, a02 = a.m02, a03 = a.m03,
- a12 = a.m06, a13 = a.m07,
- a23 = a.m11;
-
- out.m01 = a.m04;
- out.m02 = a.m08;
- out.m03 = a.m12;
- out.m04 = a01;
- out.m06 = a.m09;
- out.m07 = a.m13;
- out.m08 = a02;
- out.m09 = a12;
- out.m11 = a.m14;
- out.m12 = a03;
- out.m13 = a13;
- out.m14 = a23;
- } else {
- out.m00 = a.m00;
- out.m01 = a.m04;
- out.m02 = a.m08;
- out.m03 = a.m12;
- out.m04 = a.m01;
- out.m05 = a.m05;
- out.m06 = a.m09;
- out.m07 = a.m13;
- out.m08 = a.m02;
- out.m09 = a.m06;
- out.m10 = a.m10;
- out.m11 = a.m14;
- out.m12 = a.m03;
- out.m13 = a.m07;
- out.m14 = a.m11;
- out.m15 = a.m15;
- }
-
- return out;
-};
-
-/**
- * Inverts a mat4
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the source matrix
- * @returns {mat4} out
- */
-mat4.invert = function (out, a) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02, a03 = a.m03,
- a10 = a.m04, a11 = a.m05, a12 = a.m06, a13 = a.m07,
- a20 = a.m08, a21 = a.m09, a22 = a.m10, a23 = a.m11,
- a30 = a.m12, a31 = a.m13, a32 = a.m14, a33 = a.m15;
-
- var b00 = a00 * a11 - a01 * a10;
- var b01 = a00 * a12 - a02 * a10;
- var b02 = a00 * a13 - a03 * a10;
- var b03 = a01 * a12 - a02 * a11;
- var b04 = a01 * a13 - a03 * a11;
- var b05 = a02 * a13 - a03 * a12;
- var b06 = a20 * a31 - a21 * a30;
- var b07 = a20 * a32 - a22 * a30;
- var b08 = a20 * a33 - a23 * a30;
- var b09 = a21 * a32 - a22 * a31;
- var b10 = a21 * a33 - a23 * a31;
- var b11 = a22 * a33 - a23 * a32;
-
- // Calculate the determinant
- var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
-
- if (!det) {
- return null;
- }
- det = 1.0 / det;
-
- out.m00 = (a11 * b11 - a12 * b10 + a13 * b09) * det;
- out.m01 = (a02 * b10 - a01 * b11 - a03 * b09) * det;
- out.m02 = (a31 * b05 - a32 * b04 + a33 * b03) * det;
- out.m03 = (a22 * b04 - a21 * b05 - a23 * b03) * det;
- out.m04 = (a12 * b08 - a10 * b11 - a13 * b07) * det;
- out.m05 = (a00 * b11 - a02 * b08 + a03 * b07) * det;
- out.m06 = (a32 * b02 - a30 * b05 - a33 * b01) * det;
- out.m07 = (a20 * b05 - a22 * b02 + a23 * b01) * det;
- out.m08 = (a10 * b10 - a11 * b08 + a13 * b06) * det;
- out.m09 = (a01 * b08 - a00 * b10 - a03 * b06) * det;
- out.m10 = (a30 * b04 - a31 * b02 + a33 * b00) * det;
- out.m11 = (a21 * b02 - a20 * b04 - a23 * b00) * det;
- out.m12 = (a11 * b07 - a10 * b09 - a12 * b06) * det;
- out.m13 = (a00 * b09 - a01 * b07 + a02 * b06) * det;
- out.m14 = (a31 * b01 - a30 * b03 - a32 * b00) * det;
- out.m15 = (a20 * b03 - a21 * b01 + a22 * b00) * det;
-
- return out;
-};
-
-/**
- * Calculates the adjugate of a mat4
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the source matrix
- * @returns {mat4} out
- */
-mat4.adjoint = function (out, a) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02, a03 = a.m03,
- a10 = a.m04, a11 = a.m05, a12 = a.m06, a13 = a.m07,
- a20 = a.m08, a21 = a.m09, a22 = a.m10, a23 = a.m11,
- a30 = a.m12, a31 = a.m13, a32 = a.m14, a33 = a.m15;
-
- out.m00 = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22));
- out.m01 = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
- out.m02 = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12));
- out.m03 = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
- out.m04 = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
- out.m05 = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22));
- out.m06 = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
- out.m07 = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12));
- out.m08 = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21));
- out.m09 = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
- out.m10 = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11));
- out.m11 = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
- out.m12 = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
- out.m13 = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21));
- out.m14 = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
- out.m15 = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11));
- return out;
-};
-
-/**
- * Calculates the determinant of a mat4
- *
- * @param {mat4} a the source matrix
- * @returns {Number} determinant of a
- */
-mat4.determinant = function (a) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02, a03 = a.m03,
- a10 = a.m04, a11 = a.m05, a12 = a.m06, a13 = a.m07,
- a20 = a.m08, a21 = a.m09, a22 = a.m10, a23 = a.m11,
- a30 = a.m12, a31 = a.m13, a32 = a.m14, a33 = a.m15;
-
- var b00 = a00 * a11 - a01 * a10;
- var b01 = a00 * a12 - a02 * a10;
- var b02 = a00 * a13 - a03 * a10;
- var b03 = a01 * a12 - a02 * a11;
- var b04 = a01 * a13 - a03 * a11;
- var b05 = a02 * a13 - a03 * a12;
- var b06 = a20 * a31 - a21 * a30;
- var b07 = a20 * a32 - a22 * a30;
- var b08 = a20 * a33 - a23 * a30;
- var b09 = a21 * a32 - a22 * a31;
- var b10 = a21 * a33 - a23 * a31;
- var b11 = a22 * a33 - a23 * a32;
-
- // Calculate the determinant
- return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
-};
-
-/**
- * Multiplies two mat4's explicitly
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the first operand
- * @param {mat4} b the second operand
- * @returns {mat4} out
- */
-mat4.multiply = function (out, a, b) {
- var a00 = a.m00, a01 = a.m01, a02 = a.m02, a03 = a.m03,
- a10 = a.m04, a11 = a.m05, a12 = a.m06, a13 = a.m07,
- a20 = a.m08, a21 = a.m09, a22 = a.m10, a23 = a.m11,
- a30 = a.m12, a31 = a.m13, a32 = a.m14, a33 = a.m15;
-
- // Cache only the current line of the second matrix
- var b0 = b.m00, b1 = b.m01, b2 = b.m02, b3 = b.m03;
- out.m00 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
- out.m01 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
- out.m02 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
- out.m03 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
-
- b0 = b.m04; b1 = b.m05; b2 = b.m06; b3 = b.m07;
- out.m04 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
- out.m05 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
- out.m06 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
- out.m07 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
-
- b0 = b.m08; b1 = b.m09; b2 = b.m10; b3 = b.m11;
- out.m08 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
- out.m09 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
- out.m10 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
- out.m11 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
-
- b0 = b.m12; b1 = b.m13; b2 = b.m14; b3 = b.m15;
- out.m12 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
- out.m13 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
- out.m14 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
- out.m15 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
- return out;
-};
-
-/**
- * Alias for {@link mat4.multiply}
- * @function
- */
-mat4.mul = mat4.multiply;
-
-/**
- * Translate a mat4 by the given vector
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the matrix to translate
- * @param {vec3} v vector to translate by
- * @returns {mat4} out
- */
-mat4.translate = function (out, a, v) {
- var x = v.x, y = v.y, z = v.z,
- a00, a01, a02, a03,
- a10, a11, a12, a13,
- a20, a21, a22, a23;
-
- if (a === out) {
- out.m12 = a.m00 * x + a.m04 * y + a.m08 * z + a.m12;
- out.m13 = a.m01 * x + a.m05 * y + a.m09 * z + a.m13;
- out.m14 = a.m02 * x + a.m06 * y + a.m10 * z + a.m14;
- out.m15 = a.m03 * x + a.m07 * y + a.m11 * z + a.m15;
- } else {
- a00 = a.m00; a01 = a.m01; a02 = a.m02; a03 = a.m03;
- a10 = a.m04; a11 = a.m05; a12 = a.m06; a13 = a.m07;
- a20 = a.m08; a21 = a.m09; a22 = a.m10; a23 = a.m11;
-
- out.m00 = a00; out.m01 = a01; out.m02 = a02; out.m03 = a03;
- out.m04 = a10; out.m05 = a11; out.m06 = a12; out.m07 = a13;
- out.m08 = a20; out.m09 = a21; out.m10 = a22; out.m11 = a23;
-
- out.m12 = a00 * x + a10 * y + a20 * z + a.m12;
- out.m13 = a01 * x + a11 * y + a21 * z + a.m13;
- out.m14 = a02 * x + a12 * y + a22 * z + a.m14;
- out.m15 = a03 * x + a13 * y + a23 * z + a.m15;
- }
-
- return out;
-};
-
-/**
- * Scales the mat4 by the dimensions in the given vec3
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the matrix to scale
- * @param {vec3} v the vec3 to scale the matrix by
- * @returns {mat4} out
- **/
-mat4.scale = function (out, a, v) {
- var x = v.x, y = v.y, z = v.z;
-
- out.m00 = a.m00 * x;
- out.m01 = a.m01 * x;
- out.m02 = a.m02 * x;
- out.m03 = a.m03 * x;
- out.m04 = a.m04 * y;
- out.m05 = a.m05 * y;
- out.m06 = a.m06 * y;
- out.m07 = a.m07 * y;
- out.m08 = a.m08 * z;
- out.m09 = a.m09 * z;
- out.m10 = a.m10 * z;
- out.m11 = a.m11 * z;
- out.m12 = a.m12;
- out.m13 = a.m13;
- out.m14 = a.m14;
- out.m15 = a.m15;
- return out;
-};
-
-/**
- * Rotates a mat4 by the given angle around the given axis
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @param {vec3} axis the axis to rotate around
- * @returns {mat4} out
- */
-mat4.rotate = function (out, a, rad, axis) {
- var x = axis.x, y = axis.y, z = axis.z;
- var s, c, t,
- a00, a01, a02, a03,
- a10, a11, a12, a13,
- a20, a21, a22, a23,
- b00, b01, b02,
- b10, b11, b12,
- b20, b21, b22;
-
- var len = Math.sqrt(x * x + y * y + z * z);
-
- if (Math.abs(len) < EPSILON) {
- return null;
- }
-
- len = 1 / len;
- x *= len;
- y *= len;
- z *= len;
-
- s = Math.sin(rad);
- c = Math.cos(rad);
- t = 1 - c;
-
- a00 = a.m00; a01 = a.m01; a02 = a.m02; a03 = a.m03;
- a10 = a.m04; a11 = a.m05; a12 = a.m06; a13 = a.m07;
- a20 = a.m08; a21 = a.m09; a22 = a.m10; a23 = a.m11;
-
- // Construct the elements of the rotation matrix
- b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;
- b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;
- b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;
-
- // Perform rotation-specific matrix multiplication
- out.m00 = a00 * b00 + a10 * b01 + a20 * b02;
- out.m01 = a01 * b00 + a11 * b01 + a21 * b02;
- out.m02 = a02 * b00 + a12 * b01 + a22 * b02;
- out.m03 = a03 * b00 + a13 * b01 + a23 * b02;
- out.m04 = a00 * b10 + a10 * b11 + a20 * b12;
- out.m05 = a01 * b10 + a11 * b11 + a21 * b12;
- out.m06 = a02 * b10 + a12 * b11 + a22 * b12;
- out.m07 = a03 * b10 + a13 * b11 + a23 * b12;
- out.m08 = a00 * b20 + a10 * b21 + a20 * b22;
- out.m09 = a01 * b20 + a11 * b21 + a21 * b22;
- out.m10 = a02 * b20 + a12 * b21 + a22 * b22;
- out.m11 = a03 * b20 + a13 * b21 + a23 * b22;
-
- // If the source and destination differ, copy the unchanged last row
- if (a !== out) {
- out.m12 = a.m12;
- out.m13 = a.m13;
- out.m14 = a.m14;
- out.m15 = a.m15;
- }
-
- return out;
-};
-
-/**
- * Rotates a matrix by the given angle around the X axis
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat4} out
- */
-mat4.rotateX = function (out, a, rad) {
- var s = Math.sin(rad),
- c = Math.cos(rad),
- a10 = a.m04,
- a11 = a.m05,
- a12 = a.m06,
- a13 = a.m07,
- a20 = a.m08,
- a21 = a.m09,
- a22 = a.m10,
- a23 = a.m11;
-
- if (a !== out) { // If the source and destination differ, copy the unchanged rows
- out.m00 = a.m00;
- out.m01 = a.m01;
- out.m02 = a.m02;
- out.m03 = a.m03;
- out.m12 = a.m12;
- out.m13 = a.m13;
- out.m14 = a.m14;
- out.m15 = a.m15;
- }
-
- // Perform axis-specific matrix multiplication
- out.m04 = a10 * c + a20 * s;
- out.m05 = a11 * c + a21 * s;
- out.m06 = a12 * c + a22 * s;
- out.m07 = a13 * c + a23 * s;
- out.m08 = a20 * c - a10 * s;
- out.m09 = a21 * c - a11 * s;
- out.m10 = a22 * c - a12 * s;
- out.m11 = a23 * c - a13 * s;
-
- return out;
-};
-
-/**
- * Rotates a matrix by the given angle around the Y axis
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat4} out
- */
-mat4.rotateY = function (out, a, rad) {
- var s = Math.sin(rad),
- c = Math.cos(rad),
- a00 = a.m00,
- a01 = a.m01,
- a02 = a.m02,
- a03 = a.m03,
- a20 = a.m08,
- a21 = a.m09,
- a22 = a.m10,
- a23 = a.m11;
-
- if (a !== out) { // If the source and destination differ, copy the unchanged rows
- out.m04 = a.m04;
- out.m05 = a.m05;
- out.m06 = a.m06;
- out.m07 = a.m07;
- out.m12 = a.m12;
- out.m13 = a.m13;
- out.m14 = a.m14;
- out.m15 = a.m15;
- }
-
- // Perform axis-specific matrix multiplication
- out.m00 = a00 * c - a20 * s;
- out.m01 = a01 * c - a21 * s;
- out.m02 = a02 * c - a22 * s;
- out.m03 = a03 * c - a23 * s;
- out.m08 = a00 * s + a20 * c;
- out.m09 = a01 * s + a21 * c;
- out.m10 = a02 * s + a22 * c;
- out.m11 = a03 * s + a23 * c;
-
- return out;
-};
-
-/**
- * Rotates a matrix by the given angle around the Z axis
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat4} out
- */
-mat4.rotateZ = function (out, a, rad) {
- var s = Math.sin(rad),
- c = Math.cos(rad),
- a00 = a.m00,
- a01 = a.m01,
- a02 = a.m02,
- a03 = a.m03,
- a10 = a.m04,
- a11 = a.m05,
- a12 = a.m06,
- a13 = a.m07;
-
- // If the source and destination differ, copy the unchanged last row
- if (a !== out) {
- out.m08 = a.m08;
- out.m09 = a.m09;
- out.m10 = a.m10;
- out.m11 = a.m11;
- out.m12 = a.m12;
- out.m13 = a.m13;
- out.m14 = a.m14;
- out.m15 = a.m15;
- }
-
- // Perform axis-specific matrix multiplication
- out.m00 = a00 * c + a10 * s;
- out.m01 = a01 * c + a11 * s;
- out.m02 = a02 * c + a12 * s;
- out.m03 = a03 * c + a13 * s;
- out.m04 = a10 * c - a00 * s;
- out.m05 = a11 * c - a01 * s;
- out.m06 = a12 * c - a02 * s;
- out.m07 = a13 * c - a03 * s;
-
- return out;
-};
-
-/**
- * Creates a matrix from a vector translation
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.translate(dest, dest, vec);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {vec3} v Translation vector
- * @returns {mat4} out
- */
-mat4.fromTranslation = function (out, v) {
- out.m00 = 1;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 0;
- out.m05 = 1;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 0;
- out.m09 = 0;
- out.m10 = 1;
- out.m11 = 0;
- out.m12 = v.x;
- out.m13 = v.y;
- out.m14 = v.z;
- out.m15 = 1;
- return out;
-};
-
-/**
- * Creates a matrix from a vector scaling
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.scale(dest, dest, vec);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {vec3} v Scaling vector
- * @returns {mat4} out
- */
-mat4.fromScaling = function (out, v) {
- out.m00 = v.x;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 0;
- out.m05 = v.y;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 0;
- out.m09 = 0;
- out.m10 = v.z;
- out.m11 = 0;
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = 0;
- out.m15 = 1;
- return out;
-};
-
-/**
- * Creates a matrix from a given angle around a given axis
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.rotate(dest, dest, rad, axis);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {Number} rad the angle to rotate the matrix by
- * @param {vec3} axis the axis to rotate around
- * @returns {mat4} out
- */
-mat4.fromRotation = function (out, rad, axis) {
- var x = axis.x, y = axis.y, z = axis.z;
- var len = Math.sqrt(x * x + y * y + z * z);
- var s, c, t;
-
- if (Math.abs(len) < EPSILON) {
- return null;
- }
-
- len = 1 / len;
- x *= len;
- y *= len;
- z *= len;
-
- s = Math.sin(rad);
- c = Math.cos(rad);
- t = 1 - c;
-
- // Perform rotation-specific matrix multiplication
- out.m00 = x * x * t + c;
- out.m01 = y * x * t + z * s;
- out.m02 = z * x * t - y * s;
- out.m03 = 0;
- out.m04 = x * y * t - z * s;
- out.m05 = y * y * t + c;
- out.m06 = z * y * t + x * s;
- out.m07 = 0;
- out.m08 = x * z * t + y * s;
- out.m09 = y * z * t - x * s;
- out.m10 = z * z * t + c;
- out.m11 = 0;
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = 0;
- out.m15 = 1;
- return out;
-};
-
-/**
- * Creates a matrix from the given angle around the X axis
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.rotateX(dest, dest, rad);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat4} out
- */
-mat4.fromXRotation = function (out, rad) {
- var s = Math.sin(rad),
- c = Math.cos(rad);
-
- // Perform axis-specific matrix multiplication
- out.m00 = 1;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 0;
- out.m05 = c;
- out.m06 = s;
- out.m07 = 0;
- out.m08 = 0;
- out.m09 = -s;
- out.m10 = c;
- out.m11 = 0;
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = 0;
- out.m15 = 1;
- return out;
-};
-
-/**
- * Creates a matrix from the given angle around the Y axis
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.rotateY(dest, dest, rad);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat4} out
- */
-mat4.fromYRotation = function (out, rad) {
- var s = Math.sin(rad),
- c = Math.cos(rad);
-
- // Perform axis-specific matrix multiplication
- out.m00 = c;
- out.m01 = 0;
- out.m02 = -s;
- out.m03 = 0;
- out.m04 = 0;
- out.m05 = 1;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = s;
- out.m09 = 0;
- out.m10 = c;
- out.m11 = 0;
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = 0;
- out.m15 = 1;
- return out;
-};
-
-/**
- * Creates a matrix from the given angle around the Z axis
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.rotateZ(dest, dest, rad);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat4} out
- */
-mat4.fromZRotation = function (out, rad) {
- var s = Math.sin(rad),
- c = Math.cos(rad);
-
- // Perform axis-specific matrix multiplication
- out.m00 = c;
- out.m01 = s;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = -s;
- out.m05 = c;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 0;
- out.m09 = 0;
- out.m10 = 1;
- out.m11 = 0;
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = 0;
- out.m15 = 1;
- return out;
-};
-
-/**
- * Creates a matrix from a quaternion rotation and vector translation
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.translate(dest, vec);
- * let quatMat = mat4.create();
- * quat.toMat4(quat, quatMat);
- * mat4.multiply(dest, quatMat);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {quat} q Rotation quaternion
- * @param {vec3} v Translation vector
- * @returns {mat4} out
- */
-mat4.fromRT = function (out, q, v) {
- // Quaternion math
- var x = q.x, y = q.y, z = q.z, w = q.w;
- var x2 = x + x;
- var y2 = y + y;
- var z2 = z + z;
-
- var xx = x * x2;
- var xy = x * y2;
- var xz = x * z2;
- var yy = y * y2;
- var yz = y * z2;
- var zz = z * z2;
- var wx = w * x2;
- var wy = w * y2;
- var wz = w * z2;
-
- out.m00 = 1 - (yy + zz);
- out.m01 = xy + wz;
- out.m02 = xz - wy;
- out.m03 = 0;
- out.m04 = xy - wz;
- out.m05 = 1 - (xx + zz);
- out.m06 = yz + wx;
- out.m07 = 0;
- out.m08 = xz + wy;
- out.m09 = yz - wx;
- out.m10 = 1 - (xx + yy);
- out.m11 = 0;
- out.m12 = v.x;
- out.m13 = v.y;
- out.m14 = v.z;
- out.m15 = 1;
-
- return out;
-};
-
-/**
- * Returns the translation vector component of a transformation
- * matrix. If a matrix is built with fromRT,
- * the returned vector will be the same as the translation vector
- * originally supplied.
- * @param {vec3} out Vector to receive translation component
- * @param {mat4} mat Matrix to be decomposed (input)
- * @return {vec3} out
- */
-mat4.getTranslation = function (out, mat) {
- out.x = mat.m12;
- out.y = mat.m13;
- out.z = mat.m14;
-
- return out;
-};
-
-/**
- * Returns the scaling factor component of a transformation
- * matrix. If a matrix is built with fromRTS
- * with a normalized Quaternion paramter, the returned vector will be
- * the same as the scaling vector
- * originally supplied.
- * @param {vec3} out Vector to receive scaling factor component
- * @param {mat4} mat Matrix to be decomposed (input)
- * @return {vec3} out
- */
-mat4.getScaling = function (out, mat) {
- var m11 = mat.m00,
- m12 = mat.m01,
- m13 = mat.m02,
- m21 = mat.m04,
- m22 = mat.m05,
- m23 = mat.m06,
- m31 = mat.m08,
- m32 = mat.m09,
- m33 = mat.m10;
-
- out.x = Math.sqrt(m11 * m11 + m12 * m12 + m13 * m13);
- out.y = Math.sqrt(m21 * m21 + m22 * m22 + m23 * m23);
- out.z = Math.sqrt(m31 * m31 + m32 * m32 + m33 * m33);
-
- return out;
-};
-
-/**
- * Returns a quaternion representing the rotational component
- * of a transformation matrix. If a matrix is built with
- * fromRT, the returned quaternion will be the
- * same as the quaternion originally supplied.
- * @param {quat} out Quaternion to receive the rotation component
- * @param {mat4} mat Matrix to be decomposed (input)
- * @return {quat} out
- */
-mat4.getRotation = function (out, mat) {
- // Algorithm taken from http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
- var trace = mat.m00 + mat.m05 + mat.m10;
- var S = 0;
-
- if (trace > 0) {
- S = Math.sqrt(trace + 1.0) * 2;
- out.w = 0.25 * S;
- out.x = (mat.m06 - mat.m09) / S;
- out.y = (mat.m08 - mat.m02) / S;
- out.z = (mat.m01 - mat.m04) / S;
- } else if ((mat.m00 > mat.m05) & (mat.m00 > mat.m10)) {
- S = Math.sqrt(1.0 + mat.m00 - mat.m05 - mat.m10) * 2;
- out.w = (mat.m06 - mat.m09) / S;
- out.x = 0.25 * S;
- out.y = (mat.m01 + mat.m04) / S;
- out.z = (mat.m08 + mat.m02) / S;
- } else if (mat.m05 > mat.m10) {
- S = Math.sqrt(1.0 + mat.m05 - mat.m00 - mat.m10) * 2;
- out.w = (mat.m08 - mat.m02) / S;
- out.x = (mat.m01 + mat.m04) / S;
- out.y = 0.25 * S;
- out.z = (mat.m06 + mat.m09) / S;
- } else {
- S = Math.sqrt(1.0 + mat.m10 - mat.m00 - mat.m05) * 2;
- out.w = (mat.m01 - mat.m04) / S;
- out.x = (mat.m08 + mat.m02) / S;
- out.y = (mat.m06 + mat.m09) / S;
- out.z = 0.25 * S;
- }
-
- return out;
-};
-
-/**
- * Creates a matrix from a quaternion rotation, vector translation and vector scale
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.translate(dest, vec);
- * let quatMat = mat4.create();
- * quat.toMat4(quat, quatMat);
- * mat4.multiply(dest, quatMat);
- * mat4.scale(dest, scale)
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {quat} q Rotation quaternion
- * @param {vec3} v Translation vector
- * @param {vec3} s Scaling vector
- * @returns {mat4} out
- */
-mat4.fromRTS = function (out, q, v, s) {
- // Quaternion math
- var x = q.x, y = q.y, z = q.z, w = q.w;
- var x2 = x + x;
- var y2 = y + y;
- var z2 = z + z;
-
- var xx = x * x2;
- var xy = x * y2;
- var xz = x * z2;
- var yy = y * y2;
- var yz = y * z2;
- var zz = z * z2;
- var wx = w * x2;
- var wy = w * y2;
- var wz = w * z2;
- var sx = s.x;
- var sy = s.y;
- var sz = s.z;
-
- out.m00 = (1 - (yy + zz)) * sx;
- out.m01 = (xy + wz) * sx;
- out.m02 = (xz - wy) * sx;
- out.m03 = 0;
- out.m04 = (xy - wz) * sy;
- out.m05 = (1 - (xx + zz)) * sy;
- out.m06 = (yz + wx) * sy;
- out.m07 = 0;
- out.m08 = (xz + wy) * sz;
- out.m09 = (yz - wx) * sz;
- out.m10 = (1 - (xx + yy)) * sz;
- out.m11 = 0;
- out.m12 = v.x;
- out.m13 = v.y;
- out.m14 = v.z;
- out.m15 = 1;
-
- return out;
-};
-
-/**
- * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.translate(dest, vec);
- * mat4.translate(dest, origin);
- * let quatMat = mat4.create();
- * quat.toMat4(quat, quatMat);
- * mat4.multiply(dest, quatMat);
- * mat4.scale(dest, scale)
- * mat4.translate(dest, negativeOrigin);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {quat} q Rotation quaternion
- * @param {vec3} v Translation vector
- * @param {vec3} s Scaling vector
- * @param {vec3} o The origin vector around which to scale and rotate
- * @returns {mat4} out
- */
-mat4.fromRTSOrigin = function (out, q, v, s, o) {
- // Quaternion math
- var x = q.x, y = q.y, z = q.z, w = q.w;
- var x2 = x + x;
- var y2 = y + y;
- var z2 = z + z;
-
- var xx = x * x2;
- var xy = x * y2;
- var xz = x * z2;
- var yy = y * y2;
- var yz = y * z2;
- var zz = z * z2;
- var wx = w * x2;
- var wy = w * y2;
- var wz = w * z2;
-
- var sx = s.x;
- var sy = s.y;
- var sz = s.z;
-
- var ox = o.x;
- var oy = o.y;
- var oz = o.z;
-
- out.m00 = (1 - (yy + zz)) * sx;
- out.m01 = (xy + wz) * sx;
- out.m02 = (xz - wy) * sx;
- out.m03 = 0;
- out.m04 = (xy - wz) * sy;
- out.m05 = (1 - (xx + zz)) * sy;
- out.m06 = (yz + wx) * sy;
- out.m07 = 0;
- out.m08 = (xz + wy) * sz;
- out.m09 = (yz - wx) * sz;
- out.m10 = (1 - (xx + yy)) * sz;
- out.m11 = 0;
- out.m12 = v.x + ox - (out.m00 * ox + out.m04 * oy + out.m08 * oz);
- out.m13 = v.y + oy - (out.m01 * ox + out.m05 * oy + out.m09 * oz);
- out.m14 = v.z + oz - (out.m02 * ox + out.m06 * oy + out.m10 * oz);
- out.m15 = 1;
-
- return out;
-};
-
-/**
- * Calculates a 4x4 matrix from the given quaternion
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {quat} q Quaternion to create matrix from
- *
- * @returns {mat4} out
- */
-mat4.fromQuat = function (out, q) {
- var x = q.x, y = q.y, z = q.z, w = q.w;
- var x2 = x + x;
- var y2 = y + y;
- var z2 = z + z;
-
- var xx = x * x2;
- var yx = y * x2;
- var yy = y * y2;
- var zx = z * x2;
- var zy = z * y2;
- var zz = z * z2;
- var wx = w * x2;
- var wy = w * y2;
- var wz = w * z2;
-
- out.m00 = 1 - yy - zz;
- out.m01 = yx + wz;
- out.m02 = zx - wy;
- out.m03 = 0;
-
- out.m04 = yx - wz;
- out.m05 = 1 - xx - zz;
- out.m06 = zy + wx;
- out.m07 = 0;
-
- out.m08 = zx + wy;
- out.m09 = zy - wx;
- out.m10 = 1 - xx - yy;
- out.m11 = 0;
-
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = 0;
- out.m15 = 1;
-
- return out;
-};
-
-/**
- * Generates a frustum matrix with the given bounds
- *
- * @param {mat4} out mat4 frustum matrix will be written into
- * @param {Number} left Left bound of the frustum
- * @param {Number} right Right bound of the frustum
- * @param {Number} bottom Bottom bound of the frustum
- * @param {Number} top Top bound of the frustum
- * @param {Number} near Near bound of the frustum
- * @param {Number} far Far bound of the frustum
- * @returns {mat4} out
- */
-mat4.frustum = function (out, left, right, bottom, top, near, far) {
- var rl = 1 / (right - left);
- var tb = 1 / (top - bottom);
- var nf = 1 / (near - far);
-
- out.m00 = (near * 2) * rl;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 0;
- out.m05 = (near * 2) * tb;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = (right + left) * rl;
- out.m09 = (top + bottom) * tb;
- out.m10 = (far + near) * nf;
- out.m11 = -1;
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = (far * near * 2) * nf;
- out.m15 = 0;
- return out;
-};
-
-/**
- * Generates a perspective projection matrix with the given bounds
- *
- * @param {mat4} out mat4 frustum matrix will be written into
- * @param {number} fovy Vertical field of view in radians
- * @param {number} aspect Aspect ratio. typically viewport width/height
- * @param {number} near Near bound of the frustum
- * @param {number} far Far bound of the frustum
- * @returns {mat4} out
- */
-mat4.perspective = function (out, fovy, aspect, near, far) {
- var f = 1.0 / Math.tan(fovy / 2);
- var nf = 1 / (near - far);
-
- out.m00 = f / aspect;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 0;
- out.m05 = f;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 0;
- out.m09 = 0;
- out.m10 = (far + near) * nf;
- out.m11 = -1;
- out.m12 = 0;
- out.m13 = 0;
- out.m14 = (2 * far * near) * nf;
- out.m15 = 0;
- return out;
-};
-
-/**
- * Generates a perspective projection matrix with the given field of view.
- * This is primarily useful for generating projection matrices to be used
- * with the still experiemental WebVR API.
- *
- * @param {mat4} out mat4 frustum matrix will be written into
- * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees
- * @param {number} near Near bound of the frustum
- * @param {number} far Far bound of the frustum
- * @returns {mat4} out
- */
-mat4.perspectiveFromFieldOfView = function (out, fov, near, far) {
- var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0);
- var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0);
- var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0);
- var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0);
- var xScale = 2.0 / (leftTan + rightTan);
- var yScale = 2.0 / (upTan + downTan);
-
- out.m00 = xScale;
- out.m01 = 0.0;
- out.m02 = 0.0;
- out.m03 = 0.0;
- out.m04 = 0.0;
- out.m05 = yScale;
- out.m06 = 0.0;
- out.m07 = 0.0;
- out.m08 = -((leftTan - rightTan) * xScale * 0.5);
- out.m09 = ((upTan - downTan) * yScale * 0.5);
- out.m10 = far / (near - far);
- out.m11 = -1.0;
- out.m12 = 0.0;
- out.m13 = 0.0;
- out.m14 = (far * near) / (near - far);
- out.m15 = 0.0;
- return out;
-};
-
-/**
- * Generates a orthogonal projection matrix with the given bounds
- *
- * @param {mat4} out mat4 frustum matrix will be written into
- * @param {number} left Left bound of the frustum
- * @param {number} right Right bound of the frustum
- * @param {number} bottom Bottom bound of the frustum
- * @param {number} top Top bound of the frustum
- * @param {number} near Near bound of the frustum
- * @param {number} far Far bound of the frustum
- * @returns {mat4} out
- */
-mat4.ortho = function (out, left, right, bottom, top, near, far) {
- var lr = 1 / (left - right);
- var bt = 1 / (bottom - top);
- var nf = 1 / (near - far);
- out.m00 = -2 * lr;
- out.m01 = 0;
- out.m02 = 0;
- out.m03 = 0;
- out.m04 = 0;
- out.m05 = -2 * bt;
- out.m06 = 0;
- out.m07 = 0;
- out.m08 = 0;
- out.m09 = 0;
- out.m10 = 2 * nf;
- out.m11 = 0;
- out.m12 = (left + right) * lr;
- out.m13 = (top + bottom) * bt;
- out.m14 = (far + near) * nf;
- out.m15 = 1;
- return out;
-};
-
-/**
- * Generates a look-at matrix with the given eye position, focal point, and up axis
- *
- * @param {mat4} out mat4 frustum matrix will be written into
- * @param {vec3} eye Position of the viewer
- * @param {vec3} center Point the viewer is looking at
- * @param {vec3} up vec3 pointing up
- * @returns {mat4} out
- */
-mat4.lookAt = function (out, eye, center, up) {
- var x0, x1, x2, y0, y1, y2, z0, z1, z2, len;
- var eyex = eye.x;
- var eyey = eye.y;
- var eyez = eye.z;
- var upx = up.x;
- var upy = up.y;
- var upz = up.z;
- var centerx = center.x;
- var centery = center.y;
- var centerz = center.z;
-
- if (
- Math.abs(eyex - centerx) < EPSILON &&
- Math.abs(eyey - centery) < EPSILON &&
- Math.abs(eyez - centerz) < EPSILON
- ) {
- return mat4.identity(out);
- }
-
- z0 = eyex - centerx;
- z1 = eyey - centery;
- z2 = eyez - centerz;
-
- len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
- z0 *= len;
- z1 *= len;
- z2 *= len;
-
- x0 = upy * z2 - upz * z1;
- x1 = upz * z0 - upx * z2;
- x2 = upx * z1 - upy * z0;
- len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
- if (!len) {
- x0 = 0;
- x1 = 0;
- x2 = 0;
- } else {
- len = 1 / len;
- x0 *= len;
- x1 *= len;
- x2 *= len;
- }
-
- y0 = z1 * x2 - z2 * x1;
- y1 = z2 * x0 - z0 * x2;
- y2 = z0 * x1 - z1 * x0;
-
- len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
- if (!len) {
- y0 = 0;
- y1 = 0;
- y2 = 0;
- } else {
- len = 1 / len;
- y0 *= len;
- y1 *= len;
- y2 *= len;
- }
-
- out.m00 = x0;
- out.m01 = y0;
- out.m02 = z0;
- out.m03 = 0;
- out.m04 = x1;
- out.m05 = y1;
- out.m06 = z1;
- out.m07 = 0;
- out.m08 = x2;
- out.m09 = y2;
- out.m10 = z2;
- out.m11 = 0;
- out.m12 = -(x0 * eyex + x1 * eyey + x2 * eyez);
- out.m13 = -(y0 * eyex + y1 * eyey + y2 * eyez);
- out.m14 = -(z0 * eyex + z1 * eyey + z2 * eyez);
- out.m15 = 1;
-
- return out;
-};
-
-/**
- * Returns a string representation of a mat4
- *
- * @param {mat4} a matrix to represent as a string
- * @returns {String} string representation of the matrix
- */
-mat4.str = function (a) {
- return ("mat4(" + (a.m00) + ", " + (a.m01) + ", " + (a.m02) + ", " + (a.m03) + ", " + (a.m04) + ", " + (a.m05) + ", " + (a.m06) + ", " + (a.m07) + ", " + (a.m08) + ", " + (a.m09) + ", " + (a.m10) + ", " + (a.m11) + ", " + (a.m12) + ", " + (a.m13) + ", " + (a.m14) + ", " + (a.m15) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {mat4} m
- * @returns {array}
- */
-mat4.array = function (out, m) {
- out[0] = m.m00;
- out[1] = m.m01;
- out[2] = m.m02;
- out[3] = m.m03;
- out[4] = m.m04;
- out[5] = m.m05;
- out[6] = m.m06;
- out[7] = m.m07;
- out[8] = m.m08;
- out[9] = m.m09;
- out[10] = m.m10;
- out[11] = m.m11;
- out[12] = m.m12;
- out[13] = m.m13;
- out[14] = m.m14;
- out[15] = m.m15;
-
- return out;
-};
-
-/**
- * Returns Frobenius norm of a mat4
- *
- * @param {mat4} a the matrix to calculate Frobenius norm of
- * @returns {Number} Frobenius norm
- */
-mat4.frob = function (a) {
- return (Math.sqrt(Math.pow(a.m00, 2) + Math.pow(a.m01, 2) + Math.pow(a.m02, 2) + Math.pow(a.m03, 2) + Math.pow(a.m04, 2) + Math.pow(a.m05, 2) + Math.pow(a.m06, 2) + Math.pow(a.m07, 2) + Math.pow(a.m08, 2) + Math.pow(a.m09, 2) + Math.pow(a.m10, 2) + Math.pow(a.m11, 2) + Math.pow(a.m12, 2) + Math.pow(a.m13, 2) + Math.pow(a.m14, 2) + Math.pow(a.m15, 2)))
-};
-
-/**
- * Adds two mat4's
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the first operand
- * @param {mat4} b the second operand
- * @returns {mat4} out
- */
-mat4.add = function (out, a, b) {
- out.m00 = a.m00 + b.m00;
- out.m01 = a.m01 + b.m01;
- out.m02 = a.m02 + b.m02;
- out.m03 = a.m03 + b.m03;
- out.m04 = a.m04 + b.m04;
- out.m05 = a.m05 + b.m05;
- out.m06 = a.m06 + b.m06;
- out.m07 = a.m07 + b.m07;
- out.m08 = a.m08 + b.m08;
- out.m09 = a.m09 + b.m09;
- out.m10 = a.m10 + b.m10;
- out.m11 = a.m11 + b.m11;
- out.m12 = a.m12 + b.m12;
- out.m13 = a.m13 + b.m13;
- out.m14 = a.m14 + b.m14;
- out.m15 = a.m15 + b.m15;
- return out;
-};
-
-/**
- * Subtracts matrix b from matrix a
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the first operand
- * @param {mat4} b the second operand
- * @returns {mat4} out
- */
-mat4.subtract = function (out, a, b) {
- out.m00 = a.m00 - b.m00;
- out.m01 = a.m01 - b.m01;
- out.m02 = a.m02 - b.m02;
- out.m03 = a.m03 - b.m03;
- out.m04 = a.m04 - b.m04;
- out.m05 = a.m05 - b.m05;
- out.m06 = a.m06 - b.m06;
- out.m07 = a.m07 - b.m07;
- out.m08 = a.m08 - b.m08;
- out.m09 = a.m09 - b.m09;
- out.m10 = a.m10 - b.m10;
- out.m11 = a.m11 - b.m11;
- out.m12 = a.m12 - b.m12;
- out.m13 = a.m13 - b.m13;
- out.m14 = a.m14 - b.m14;
- out.m15 = a.m15 - b.m15;
- return out;
-};
-
-/**
- * Alias for {@link mat4.subtract}
- * @function
- */
-mat4.sub = mat4.subtract;
-
-/**
- * Multiply each element of the matrix by a scalar.
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the matrix to scale
- * @param {Number} b amount to scale the matrix's elements by
- * @returns {mat4} out
- */
-mat4.multiplyScalar = function (out, a, b) {
- out.m00 = a.m00 * b;
- out.m01 = a.m01 * b;
- out.m02 = a.m02 * b;
- out.m03 = a.m03 * b;
- out.m04 = a.m04 * b;
- out.m05 = a.m05 * b;
- out.m06 = a.m06 * b;
- out.m07 = a.m07 * b;
- out.m08 = a.m08 * b;
- out.m09 = a.m09 * b;
- out.m10 = a.m10 * b;
- out.m11 = a.m11 * b;
- out.m12 = a.m12 * b;
- out.m13 = a.m13 * b;
- out.m14 = a.m14 * b;
- out.m15 = a.m15 * b;
- return out;
-};
-
-/**
- * Adds two mat4's after multiplying each element of the second operand by a scalar value.
- *
- * @param {mat4} out the receiving vector
- * @param {mat4} a the first operand
- * @param {mat4} b the second operand
- * @param {Number} scale the amount to scale b's elements by before adding
- * @returns {mat4} out
- */
-mat4.multiplyScalarAndAdd = function (out, a, b, scale) {
- out.m00 = a.m00 + (b.m00 * scale);
- out.m01 = a.m01 + (b.m01 * scale);
- out.m02 = a.m02 + (b.m02 * scale);
- out.m03 = a.m03 + (b.m03 * scale);
- out.m04 = a.m04 + (b.m04 * scale);
- out.m05 = a.m05 + (b.m05 * scale);
- out.m06 = a.m06 + (b.m06 * scale);
- out.m07 = a.m07 + (b.m07 * scale);
- out.m08 = a.m08 + (b.m08 * scale);
- out.m09 = a.m09 + (b.m09 * scale);
- out.m10 = a.m10 + (b.m10 * scale);
- out.m11 = a.m11 + (b.m11 * scale);
- out.m12 = a.m12 + (b.m12 * scale);
- out.m13 = a.m13 + (b.m13 * scale);
- out.m14 = a.m14 + (b.m14 * scale);
- out.m15 = a.m15 + (b.m15 * scale);
- return out;
-};
-
-/**
- * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
- *
- * @param {mat4} a The first matrix.
- * @param {mat4} b The second matrix.
- * @returns {Boolean} True if the matrices are equal, false otherwise.
- */
-mat4.exactEquals = function (a, b) {
- return a.m00 === b.m00 && a.m01 === b.m01 && a.m02 === b.m02 && a.m03 === b.m03 &&
- a.m04 === b.m04 && a.m05 === b.m05 && a.m06 === b.m06 && a.m07 === b.m07 &&
- a.m08 === b.m08 && a.m09 === b.m09 && a.m10 === b.m10 && a.m11 === b.m11 &&
- a.m12 === b.m12 && a.m13 === b.m13 && a.m14 === b.m14 && a.m15 === b.m15;
-};
-
-/**
- * Returns whether or not the matrices have approximately the same elements in the same position.
- *
- * @param {mat4} a The first matrix.
- * @param {mat4} b The second matrix.
- * @returns {Boolean} True if the matrices are equal, false otherwise.
- */
-mat4.equals = function (a, b) {
- var a0 = a.m00, a1 = a.m01, a2 = a.m02, a3 = a.m03,
- a4 = a.m04, a5 = a.m05, a6 = a.m06, a7 = a.m07,
- a8 = a.m08, a9 = a.m09, a10 = a.m10, a11 = a.m11,
- a12 = a.m12, a13 = a.m13, a14 = a.m14, a15 = a.m15;
-
- var b0 = b.m00, b1 = b.m01, b2 = b.m02, b3 = b.m03,
- b4 = b.m04, b5 = b.m05, b6 = b.m06, b7 = b.m07,
- b8 = b.m08, b9 = b.m09, b10 = b.m10, b11 = b.m11,
- b12 = b.m12, b13 = b.m13, b14 = b.m14, b15 = b.m15;
-
- return (
- Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
- Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
- Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&
- Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&
- Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&
- Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&
- Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) &&
- Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8)) &&
- Math.abs(a9 - b9) <= EPSILON * Math.max(1.0, Math.abs(a9), Math.abs(b9)) &&
- Math.abs(a10 - b10) <= EPSILON * Math.max(1.0, Math.abs(a10), Math.abs(b10)) &&
- Math.abs(a11 - b11) <= EPSILON * Math.max(1.0, Math.abs(a11), Math.abs(b11)) &&
- Math.abs(a12 - b12) <= EPSILON * Math.max(1.0, Math.abs(a12), Math.abs(b12)) &&
- Math.abs(a13 - b13) <= EPSILON * Math.max(1.0, Math.abs(a13), Math.abs(b13)) &&
- Math.abs(a14 - b14) <= EPSILON * Math.max(1.0, Math.abs(a14), Math.abs(b14)) &&
- Math.abs(a15 - b15) <= EPSILON * Math.max(1.0, Math.abs(a15), Math.abs(b15))
- );
-};
-
-var _tmp$8 = new Array(3);
-
-var _color3 = function _color3(r, g, b) {
- this.r = r;
- this.g = g;
- this.b = b;
-};
-
-_color3.prototype.toJSON = function toJSON () {
- _tmp$8[0] = this.r;
- _tmp$8[1] = this.g;
- _tmp$8[2] = this.b;
-
- return _tmp$8;
-};
-
-/**
- * @class Color
- * @name color3
- */
-var color3 = {};
-
-/**
- * Creates a new color
- *
- * @returns {color3} a new color
- */
-color3.create = function () {
- return new _color3(1, 1, 1);
-};
-
-/**
- * Creates a new color initialized with the given values
- *
- * @param {Number} r red component
- * @param {Number} g green component
- * @param {Number} b blue component
- * @returns {color3} a new color
- * @function
- */
-color3.new = function (r, g, b) {
- return new _color3(r, g, b);
-};
-
-/**
- * Creates a new color initialized with values from an existing quaternion
- *
- * @param {color3} a color to clone
- * @returns {color3} a new color
- * @function
- */
-color3.clone = function (a) {
- return new _color3(a.r, a.g, a.b, a.a);
-};
-
-/**
- * Copy the values from one color to another
- *
- * @param {color3} out the receiving color
- * @param {color3} a the source color
- * @returns {color3} out
- * @function
- */
-color3.copy = function (out, a) {
- out.r = a.r;
- out.g = a.g;
- out.b = a.b;
- return out;
-};
-
-/**
- * Set the components of a color to the given values
- *
- * @param {color3} out the receiving color
- * @param {Number} r red component
- * @param {Number} g green component
- * @param {Number} b blue component
- * @returns {color3} out
- * @function
- */
-color3.set = function (out, r, g, b) {
- out.r = r;
- out.g = g;
- out.b = b;
- return out;
-};
-
-/**
- * Set from hex
- *
- * @param {color3} out the receiving color
- * @param {Number} hex
- * @returns {color3} out
- * @function
- */
-color3.fromHex = function (out, hex) {
- var r = ((hex >> 16)) / 255.0;
- var g = ((hex >> 8) & 0xff) / 255.0;
- var b = ((hex) & 0xff) / 255.0;
-
- out.r = r;
- out.g = g;
- out.b = b;
- return out;
-};
-
-/**
- * Adds two color's
- *
- * @param {color3} out the receiving color
- * @param {color3} a the first operand
- * @param {color3} b the second operand
- * @returns {color3} out
- * @function
- */
-color3.add = function (out, a, b) {
- out.r = a.r + b.r;
- out.g = a.g + b.g;
- out.b = a.b + b.b;
- return out;
-};
-
-/**
- * Subtracts color b from color a
- *
- * @param {color3} out the receiving color
- * @param {color3} a the first operand
- * @param {color3} b the second operand
- * @returns {color3} out
- */
-color3.subtract = function (out, a, b) {
- out.r = a.r - b.r;
- out.g = a.g - b.g;
- out.b = a.b - b.b;
- return out;
-};
-
-/**
- * Alias for {@link color3.subtract}
- * @function
- */
-color3.sub = color3.subtract;
-
-/**
- * Multiplies two color's
- *
- * @param {color3} out the receiving color
- * @param {color3} a the first operand
- * @param {color3} b the second operand
- * @returns {color3} out
- * @function
- */
-color3.multiply = function (out, a, b) {
- out.r = a.r * b.r;
- out.g = a.g * b.g;
- out.b = a.b * b.b;
- return out;
-};
-
-/**
- * Alias for {@link color3.multiply}
- * @function
- */
-color3.mul = color3.multiply;
-
-/**
- * Divides two color's
- *
- * @param {color3} out the receiving vector
- * @param {color3} a the first operand
- * @param {color3} b the second operand
- * @returns {color3} out
- */
-color3.divide = function (out, a, b) {
- out.r = a.r / b.r;
- out.g = a.g / b.g;
- out.b = a.b / b.b;
- return out;
-};
-
-/**
- * Alias for {@link color3.divide}
- * @function
- */
-color3.div = color3.divide;
-
-
-/**
- * Scales a color by a scalar number
- *
- * @param {color3} out the receiving vector
- * @param {color3} a the vector to scale
- * @param {Number} b amount to scale the vector by
- * @returns {color3} out
- * @function
- */
-color3.scale = function (out, a, b) {
- out.r = a.r * b;
- out.g = a.g * b;
- out.b = a.b * b;
- return out;
-};
-
-/**
- * Performs a linear interpolation between two color's
- *
- * @param {color3} out the receiving color
- * @param {color3} a the first operand
- * @param {color3} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {color3} out
- * @function
- */
-color3.lerp = function (out, a, b, t) {
- var ar = a.r,
- ag = a.g,
- ab = a.b;
- out.r = ar + t * (b.r - ar);
- out.g = ag + t * (b.g - ag);
- out.b = ab + t * (b.b - ab);
- return out;
-};
-
-/**
- * Returns a string representation of a color
- *
- * @param {color3} a vector to represent as a string
- * @returns {String} string representation of the vector
- */
-color3.str = function (a) {
- return ("color3(" + (a.r) + ", " + (a.g) + ", " + (a.b) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {color3} a
- * @returns {array}
- */
-color3.array = function (out, a) {
- out[0] = a.r;
- out[1] = a.g;
- out[2] = a.b;
-
- return out;
-};
-
-/**
- * Returns whether or not the color have exactly the same elements in the same position (when compared with ===)
- *
- * @param {color3} a The first color3.
- * @param {color3} b The second color3.
- * @returns {Boolean} True if the colors are equal, false otherwise.
- */
-color3.exactEquals = function (a, b) {
- return a.r === b.r && a.g === b.g && a.b === b.b;
-};
-
-/**
- * Returns whether or not the colors have approximately the same elements in the same position.
- *
- * @param {color3} a The first color3.
- * @param {color3} b The second color3.
- * @returns {Boolean} True if the colors are equal, false otherwise.
- */
-color3.equals = function (a, b) {
- var a0 = a.r, a1 = a.g, a2 = a.b;
- var b0 = b.r, b1 = b.g, b2 = b.b;
- return (Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
- Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)));
-};
-
-/**
- * Returns the hex value
- *
- * @param {color3} a The color
- * @returns {Number}
- */
-color3.hex = function (a) {
- return (a.r * 255) << 16 | (a.g * 255) << 8 | (a.b * 255);
-};
-
-var _tmp$9 = new Array(4);
-
-var _color4 = function _color4(r, g, b, a) {
- this.r = r;
- this.g = g;
- this.b = b;
- this.a = a;
-};
-
-_color4.prototype.toJSON = function toJSON () {
- _tmp$9[0] = this.r;
- _tmp$9[1] = this.g;
- _tmp$9[2] = this.b;
- _tmp$9[3] = this.a;
-
- return _tmp$9;
-};
-
-/**
- * @class Color
- * @name color4
- */
-var color4 = {};
-
-/**
- * Creates a new color
- *
- * @returns {color4} a new color
- */
-color4.create = function () {
- return new _color4(1, 1, 1, 1);
-};
-
-/**
- * Creates a new color initialized with the given values
- *
- * @param {Number} r red component
- * @param {Number} g green component
- * @param {Number} b blue component
- * @param {Number} a alpha component
- * @returns {color4} a new color
- * @function
- */
-color4.new = function (r, g, b, a) {
- return new _color4(r, g, b, a);
-};
-
-/**
- * Creates a new color initialized with values from an existing quaternion
- *
- * @param {color4} a color to clone
- * @returns {color4} a new color
- * @function
- */
-color4.clone = function (a) {
- return new _color4(a.r, a.g, a.b, a.a);
-};
-
-/**
- * Copy the values from one color to another
- *
- * @param {color4} out the receiving color
- * @param {color4} a the source color
- * @returns {color4} out
- * @function
- */
-color4.copy = function (out, a) {
- out.r = a.r;
- out.g = a.g;
- out.b = a.b;
- out.a = a.a;
- return out;
-};
-
-/**
- * Set the components of a color to the given values
- *
- * @param {color4} out the receiving color
- * @param {Number} r red component
- * @param {Number} g green component
- * @param {Number} b blue component
- * @param {Number} a alpha component
- * @returns {color4} out
- * @function
- */
-color4.set = function (out, r, g, b, a) {
- out.r = r;
- out.g = g;
- out.b = b;
- out.a = a;
- return out;
-};
-
-/**
- * Set from hex
- *
- * @param {color4} out the receiving color
- * @param {Number} hex
- * @returns {color4} out
- * @function
- */
-color4.fromHex = function (out, hex) {
- var r = ((hex >> 24)) / 255.0;
- var g = ((hex >> 16) & 0xff) / 255.0;
- var b = ((hex >> 8) & 0xff) / 255.0;
- var a = ((hex) & 0xff) / 255.0;
-
- out.r = r;
- out.g = g;
- out.b = b;
- out.a = a;
- return out;
-};
-
-/**
- * Adds two color's
- *
- * @param {color4} out the receiving color
- * @param {color4} a the first operand
- * @param {color4} b the second operand
- * @returns {color4} out
- * @function
- */
-color4.add = function (out, a, b) {
- out.r = a.r + b.r;
- out.g = a.g + b.g;
- out.b = a.b + b.b;
- out.a = a.a + b.a;
- return out;
-};
-
-/**
- * Subtracts color b from color a
- *
- * @param {color4} out the receiving color
- * @param {color4} a the first operand
- * @param {color4} b the second operand
- * @returns {color4} out
- */
-color4.subtract = function (out, a, b) {
- out.r = a.r - b.r;
- out.g = a.g - b.g;
- out.b = a.b - b.b;
- out.a = a.a - b.a;
- return out;
-};
-
-/**
- * Alias for {@link color4.subtract}
- * @function
- */
-color4.sub = color4.subtract;
-
-/**
- * Multiplies two color's
- *
- * @param {color4} out the receiving color
- * @param {color4} a the first operand
- * @param {color4} b the second operand
- * @returns {color4} out
- * @function
- */
-color4.multiply = function (out, a, b) {
- out.r = a.r * b.r;
- out.g = a.g * b.g;
- out.b = a.b * b.b;
- out.a = a.a * b.a;
- return out;
-};
-
-/**
- * Alias for {@link color4.multiply}
- * @function
- */
-color4.mul = color4.multiply;
-
-/**
- * Divides two color's
- *
- * @param {color4} out the receiving vector
- * @param {color4} a the first operand
- * @param {color4} b the second operand
- * @returns {color4} out
- */
-color4.divide = function (out, a, b) {
- out.r = a.r / b.r;
- out.g = a.g / b.g;
- out.b = a.b / b.b;
- out.a = a.a / b.a;
- return out;
-};
-
-/**
- * Alias for {@link color4.divide}
- * @function
- */
-color4.div = color4.divide;
-
-
-/**
- * Scales a color by a scalar number
- *
- * @param {color4} out the receiving vector
- * @param {color4} a the vector to scale
- * @param {Number} b amount to scale the vector by
- * @returns {color4} out
- * @function
- */
-color4.scale = function (out, a, b) {
- out.r = a.r * b;
- out.g = a.g * b;
- out.b = a.b * b;
- out.a = a.a * b;
- return out;
-};
-
-/**
- * Performs a linear interpolation between two color's
- *
- * @param {color4} out the receiving color
- * @param {color4} a the first operand
- * @param {color4} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {color4} out
- * @function
- */
-color4.lerp = function (out, a, b, t) {
- var ar = a.r,
- ag = a.g,
- ab = a.b,
- aa = a.a;
- out.r = ar + t * (b.r - ar);
- out.g = ag + t * (b.g - ag);
- out.b = ab + t * (b.b - ab);
- out.a = aa + t * (b.a - aa);
- return out;
-};
-
-/**
- * Returns a string representation of a color
- *
- * @param {color4} a vector to represent as a string
- * @returns {String} string representation of the vector
- */
-color4.str = function (a) {
- return ("color4(" + (a.r) + ", " + (a.g) + ", " + (a.b) + ", " + (a.a) + ")");
-};
-
-/**
- * Returns typed array
- *
- * @param {array} out
- * @param {color4} a
- * @returns {array}
- */
-color4.array = function (out, a) {
- out[0] = a.r;
- out[1] = a.g;
- out[2] = a.b;
- out[3] = a.a;
-
- return out;
-};
-
-/**
- * Returns whether or not the color have exactly the same elements in the same position (when compared with ===)
- *
- * @param {color4} a The first color4.
- * @param {color4} b The second color4.
- * @returns {Boolean} True if the colors are equal, false otherwise.
- */
-color4.exactEquals = function (a, b) {
- return a.r === b.r && a.g === b.g && a.b === b.b && a.a === b.a;
-};
-
-/**
- * Returns whether or not the colors have approximately the same elements in the same position.
- *
- * @param {color4} a The first color4.
- * @param {color4} b The second color4.
- * @returns {Boolean} True if the colors are equal, false otherwise.
- */
-color4.equals = function (a, b) {
- var a0 = a.r, a1 = a.g, a2 = a.b, a3 = a.a;
- var b0 = b.r, b1 = b.g, b2 = b.b, b3 = b.a;
- return (Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
- Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
- Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
- Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)));
-};
-
-/**
- * Returns the hex value
- *
- * @param {color4} a The color
- * @returns {Number}
- */
-color4.hex = function (a) {
- return ((a.r * 255) << 24 | (a.g * 255) << 16 | (a.b * 255) << 8 | a.a * 255) >>> 0;
-};
-
-// NOTE: there is no syntax for: export {* as bits} from './lib/bits';
-var bits = bits_;
-
-
-
-var math = Object.freeze({
- bits: bits,
- vec2: vec2,
- vec3: vec3,
- vec4: vec4,
- quat: quat,
- mat2: mat2,
- mat23: mat23,
- mat3: mat3,
- mat4: mat4,
- color3: color3,
- color4: color4,
- EPSILON: EPSILON,
- equals: equals,
- approx: approx,
- clamp: clamp,
- clamp01: clamp01,
- lerp: lerp,
- toRadian: toRadian,
- toDegree: toDegree,
- random: random,
- randomRange: randomRange,
- randomRangeInt: randomRangeInt,
- nextPow2: nextPow2
-});
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var Device = function Device(canvasEL) {
- var ctx;
-
- try {
- ctx = canvasEL.getContext('2d');
- } catch (err) {
- console.error(err);
- return;
- }
-
- // statics
- this._canvas = canvasEL;
- this._ctx = ctx;
- this._caps = {}; // capability
- this._stats = {
- drawcalls: 0,
- };
-
- // runtime
- this._vx = this._vy = this._vw = this._vh = 0;
- this._sx = this._sy = this._sw = this._sh = 0;
-};
-
-Device.prototype._restoreTexture = function _restoreTexture (unit) {
-};
-
-// ===============================
-// Immediate Settings
-// ===============================
-
-/**
- * @method setViewport
- * @param {Number} x
- * @param {Number} y
- * @param {Number} w
- * @param {Number} h
- */
-Device.prototype.setViewport = function setViewport (x, y, w, h) {
- if (
- this._vx !== x ||
- this._vy !== y ||
- this._vw !== w ||
- this._vh !== h
- ) {
- this._vx = x;
- this._vy = y;
- this._vw = w;
- this._vh = h;
- }
-};
-
-/**
- * @method setScissor
- * @param {Number} x
- * @param {Number} y
- * @param {Number} w
- * @param {Number} h
- */
-Device.prototype.setScissor = function setScissor (x, y, w, h) {
- if (
- this._sx !== x ||
- this._sy !== y ||
- this._sw !== w ||
- this._sh !== h
- ) {
- this._sx = x;
- this._sy = y;
- this._sw = w;
- this._sh = h;
- }
-};
-
-Device.prototype.clear = function clear (color) {
- var ctx = this._ctx;
- ctx.clearRect(this._vx, this._vy, this._vw, this._vh);
- if (color && (color[0] !== 0 || color[1] !== 0 || color[2] !== 0)) {
- ctx.fillStyle = 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] +')';
- ctx.globalAlpha = color[3];
- ctx.fillRect(this._vx, this._vy, this._vw, this._vh);
- }
-};
-
-// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
-var Texture2D = function Texture2D(device, options) {
- this._device = device;
-
- this._width = 4;
- this._height = 4;
-
- this._image = null;
-
- if (options) {
- if (options.width !== undefined) {
- this._width = options.width;
- }
- if (options.height !== undefined) {
- this._height = options.height;
- }
-
- this.updateImage(options);
- }
-};
-
-Texture2D.prototype.update = function update (options) {
- this.updateImage(options);
-};
-
-Texture2D.prototype.updateImage = function updateImage (options) {
- if (options.images && options.images[0]) {
- var image = options.images[0];
- if (image && image !== this._image) {
- this._image = image;
- }
- }
-};
-
-Texture2D.prototype.destroy = function destroy () {
- this._image = null;
-};
-
-var canvas = {
- Device: Device,
- Texture2D: Texture2D
-};
-
-// intenral
-// deps
-// Add stage to renderer
-renderer$3.config.addStage('transparent');
-
-var renderEngine = {
- // core classes
- Device: gfx$1.Device,
- ForwardRenderer: renderer$3.ForwardRenderer,
- Texture2D: gfx$1.Texture2D,
-
- // Canvas render support
- canvas: canvas,
-
- // render scene
- Scene: renderer$3.Scene,
- Camera: renderer$3.Camera,
- View: renderer$3.View,
- Model: renderer$3.Model,
- RenderData: RenderData,
- IARenderData: IARenderData,
- InputAssembler: renderer$3.InputAssembler,
-
- // assets
- Asset: Asset,
- TextureAsset: Texture,
- Material: Material,
-
- // materials
- SpriteMaterial: SpriteMaterial,
- GraySpriteMaterial: GraySpriteMaterial,
- StencilMaterial: StencilMaterial,
-
- // shaders
- shaders: shaders,
-
- // memop
- RecyclePool: RecyclePool,
- Pool: Pool,
-
- // modules
- math: math,
- renderer: renderer$3,
- gfx: gfx$1,
-};
-
-module.exports = renderEngine;
diff --git a/cocos2d/core/renderer/render-flow.js b/cocos2d/core/renderer/render-flow.js
index 14e020a7b6a..444e76893bc 100644
--- a/cocos2d/core/renderer/render-flow.js
+++ b/cocos2d/core/renderer/render-flow.js
@@ -1,21 +1,22 @@
-const DONOTHING = 0;
-const LOCAL_TRANSFORM = 1 << 0;
-const WORLD_TRANSFORM = 1 << 1;
+let FlagOfset = 0;
+
+const DONOTHING = 1 << FlagOfset++;
+const BREAK_FLOW = 1 << FlagOfset++;
+const LOCAL_TRANSFORM = 1 << FlagOfset++;
+const WORLD_TRANSFORM = 1 << FlagOfset++;
const TRANSFORM = LOCAL_TRANSFORM | WORLD_TRANSFORM;
-const UPDATE_RENDER_DATA = 1 << 2;
-const OPACITY = 1 << 3;
-const COLOR = 1 << 4;
-const RENDER = 1 << 5;
-const CUSTOM_IA_RENDER = 1 << 6;
-const CHILDREN = 1 << 7;
-const POST_UPDATE_RENDER_DATA = 1 << 8;
-const POST_RENDER = 1 << 9;
-const FINAL = 1 << 10;
-
-let _walker = null;
+const UPDATE_RENDER_DATA = 1 << FlagOfset++;
+const OPACITY = 1 << FlagOfset++;
+const COLOR = 1 << FlagOfset++;
+const OPACITY_COLOR = OPACITY | COLOR;
+const RENDER = 1 << FlagOfset++;
+const CHILDREN = 1 << FlagOfset++;
+const POST_RENDER = 1 << FlagOfset++;
+const FINAL = 1 << FlagOfset++;
+
+let _batcher, _forward;
let _cullingMask = 0;
-//
function RenderFlow () {
this._func = init;
this._next = null;
@@ -32,18 +33,29 @@ _proto._localTransform = function (node) {
};
_proto._worldTransform = function (node) {
- _walker.worldMatDirty ++;
+ _batcher.worldMatDirty ++;
let t = node._matrix;
- let position = node._position;
- t.m12 = position.x;
- t.m13 = position.y;
+ let trs = node._trs;
+ let tm = t.m;
+ tm[12] = trs[0];
+ tm[13] = trs[1];
+ tm[14] = trs[2];
node._mulMat(node._worldMatrix, node._parent._worldMatrix, t);
node._renderFlag &= ~WORLD_TRANSFORM;
this._next._func(node);
- _walker.worldMatDirty --;
+ _batcher.worldMatDirty --;
+};
+
+_proto._opacity = function (node) {
+ _batcher.parentOpacityDirty++;
+
+ this._next._func(node);
+
+ node._renderFlag &= ~OPACITY;
+ _batcher.parentOpacityDirty--;
};
_proto._color = function (node) {
@@ -51,19 +63,9 @@ _proto._color = function (node) {
if (comp) {
comp._updateColor();
}
- else {
- node._renderFlag &= ~COLOR;
- }
- this._next._func(node);
-};
-
-_proto._opacity = function (node) {
- _walker.parentOpacityDirty++;
- node._renderFlag &= ~OPACITY;
+ node._renderFlag &= ~COLOR;
this._next._func(node);
-
- _walker.parentOpacityDirty--;
};
_proto._updateRenderData = function (node) {
@@ -75,55 +77,49 @@ _proto._updateRenderData = function (node) {
_proto._render = function (node) {
let comp = node._renderComponent;
- _walker._commitComp(comp, comp._assembler, node._cullingMask);
+ comp._checkBacth(_batcher, node._cullingMask);
+ comp._assembler.fillBuffers(comp, _batcher);
this._next._func(node);
};
-_proto._customIARender = function (node) {
- let comp = node._renderComponent;
- _walker._commitIA(comp, comp._assembler, node._cullingMask);
- this._next._func(node);
-};
_proto._children = function (node) {
let cullingMask = _cullingMask;
+ let batcher = _batcher;
- let parentOpacity = _walker.parentOpacity;
- _walker.parentOpacity *= (node._opacity / 255);
+ let parentOpacity = batcher.parentOpacity;
+ let opacity = (batcher.parentOpacity *= (node._opacity / 255));
- let worldTransformFlag = _walker.worldMatDirty ? WORLD_TRANSFORM : 0;
- let worldOpacityFlag = _walker.parentOpacityDirty ? COLOR : 0;
+ let worldTransformFlag = batcher.worldMatDirty ? WORLD_TRANSFORM : 0;
+ let worldOpacityFlag = batcher.parentOpacityDirty ? OPACITY_COLOR : 0;
+ let worldDirtyFlag = worldTransformFlag | worldOpacityFlag;
let children = node._children;
for (let i = 0, l = children.length; i < l; i++) {
let c = children[i];
- if (!c._activeInHierarchy) continue;
+
+ // Advance the modification of the flag to avoid node attribute modification is invalid when opacity === 0.
+ c._renderFlag |= worldDirtyFlag;
+ if (!c._activeInHierarchy || c._opacity === 0) continue;
+
_cullingMask = c._cullingMask = c.groupIndex === 0 ? cullingMask : 1 << c.groupIndex;
- c._renderFlag |= worldTransformFlag | worldOpacityFlag;
// TODO: Maybe has better way to implement cascade opacity
- c._color.a = c._opacity * _walker.parentOpacity;
+ let colorVal = c._color._val;
+ c._color._fastSetA(c._opacity * opacity);
flows[c._renderFlag]._func(c);
- c._color.a = 255;
+ c._color._val = colorVal;
}
- _walker.parentOpacity = parentOpacity;
-
- this._next._func(node);
-
- _cullingMask = cullingMask;
-};
+ batcher.parentOpacity = parentOpacity;
-_proto._postUpdateRenderData = function (node) {
- let comp = node._renderComponent;
- comp._postAssembler && comp._postAssembler.updateRenderData(comp);
- node._renderFlag &= ~POST_UPDATE_RENDER_DATA;
this._next._func(node);
};
_proto._postRender = function (node) {
let comp = node._renderComponent;
- _walker._commitComp(comp, comp._postAssembler, node._cullingMask);
+ comp._checkBacth(_batcher, node._cullingMask);
+ comp._assembler.postFillBuffers(comp, _batcher);
this._next._func(node);
};
@@ -141,33 +137,30 @@ function createFlow (flag, next) {
case DONOTHING:
flow._func = flow._doNothing;
break;
+ case BREAK_FLOW:
+ flow._func = flow._doNothing;
+ break;
case LOCAL_TRANSFORM:
flow._func = flow._localTransform;
break;
case WORLD_TRANSFORM:
flow._func = flow._worldTransform;
break;
- case COLOR:
- flow._func = flow._color;
- break;
case OPACITY:
flow._func = flow._opacity;
break;
+ case COLOR:
+ flow._func = flow._color;
+ break;
case UPDATE_RENDER_DATA:
flow._func = flow._updateRenderData;
break;
case RENDER:
flow._func = flow._render;
break;
- case CUSTOM_IA_RENDER:
- flow._func = flow._customIARender;
- break;
case CHILDREN:
flow._func = flow._children;
break;
- case POST_UPDATE_RENDER_DATA:
- flow._func = flow._postUpdateRenderData;
- break;
case POST_RENDER:
flow._func = flow._postRender;
break;
@@ -187,24 +180,6 @@ function getFlow (flag) {
return flow;
}
-
-function render (scene) {
- _cullingMask = 1 << scene.groupIndex;
-
- if (scene._renderFlag & WORLD_TRANSFORM) {
- _walker.worldMatDirty ++;
- scene._calculWorldMatrix();
- scene._renderFlag &= ~WORLD_TRANSFORM;
-
- flows[scene._renderFlag]._func(scene);
-
- _walker.worldMatDirty --;
- }
- else {
- flows[scene._renderFlag]._func(scene);
- }
-}
-
//
function init (node) {
let flag = node._renderFlag;
@@ -214,30 +189,102 @@ function init (node) {
RenderFlow.flows = flows;
RenderFlow.createFlow = createFlow;
-RenderFlow.render = render;
-RenderFlow.init = function (walker) {
- _walker = walker;
+// validate whether render component is ready to be rendered.
+let _validateList = [];
+RenderFlow.registerValidate = function (renderComp) {
+ if (renderComp._inValidateList) return;
+ _validateList.push(renderComp);
+ renderComp._inValidateList = true;
+};
+RenderFlow.validateRenderers = function () {
+ for (let i = 0, l = _validateList.length; i < l; i++) {
+ let renderComp = _validateList[i];
+ if (!renderComp.isValid) continue;
+ if (!renderComp.enabledInHierarchy) {
+ renderComp.disableRender();
+ }
+ else {
+ renderComp._validateRender();
+ }
+ renderComp._inValidateList = false;
+ }
+ _validateList.length = 0;
+};
- flows[0] = EMPTY_FLOW;
+RenderFlow.visitRootNode = function (rootNode) {
+ RenderFlow.validateRenderers();
+
+ let preCullingMask = _cullingMask;
+ _cullingMask = rootNode._cullingMask;
+
+ if (rootNode._renderFlag & WORLD_TRANSFORM) {
+ _batcher.worldMatDirty ++;
+ rootNode._calculWorldMatrix();
+ rootNode._renderFlag &= ~WORLD_TRANSFORM;
+
+ flows[rootNode._renderFlag]._func(rootNode);
+
+ _batcher.worldMatDirty --;
+ }
+ else {
+ flows[rootNode._renderFlag]._func(rootNode);
+ }
+
+ _cullingMask = preCullingMask;
+};
+
+RenderFlow.render = function (rootNode, dt) {
+ _batcher.reset();
+ _batcher.walking = true;
+
+ RenderFlow.visitRootNode(rootNode);
+
+ _batcher.terminate();
+ _batcher.walking = false;
+
+ _forward.render(_batcher._renderScene, dt);
+};
+
+RenderFlow.renderCamera = function (camera, rootNode) {
+ _batcher.reset();
+ _batcher.walking = true;
+
+ RenderFlow.visitRootNode(rootNode);
+
+ _batcher.terminate();
+ _batcher.walking = false;
+
+ _forward.renderCamera(camera, _batcher._renderScene);
+};
+
+RenderFlow.init = function (batcher, forwardRenderer) {
+ _batcher = batcher;
+ _forward = forwardRenderer;
+
+ flows[0] = EMPTY_FLOW;
for (let i = 1; i < FINAL; i++) {
flows[i] = new RenderFlow();
}
};
+RenderFlow.getBachther = function () {
+ return _batcher;
+};
+
RenderFlow.FLAG_DONOTHING = DONOTHING;
+RenderFlow.FLAG_BREAK_FLOW = BREAK_FLOW;
RenderFlow.FLAG_LOCAL_TRANSFORM = LOCAL_TRANSFORM;
RenderFlow.FLAG_WORLD_TRANSFORM = WORLD_TRANSFORM;
RenderFlow.FLAG_TRANSFORM = TRANSFORM;
-RenderFlow.FLAG_COLOR = COLOR;
RenderFlow.FLAG_OPACITY = OPACITY;
+RenderFlow.FLAG_COLOR = COLOR;
+RenderFlow.FLAG_OPACITY_COLOR = OPACITY_COLOR;
RenderFlow.FLAG_UPDATE_RENDER_DATA = UPDATE_RENDER_DATA;
RenderFlow.FLAG_RENDER = RENDER;
-RenderFlow.FLAG_CUSTOM_IA_RENDER = CUSTOM_IA_RENDER;
RenderFlow.FLAG_CHILDREN = CHILDREN;
-RenderFlow.FLAG_POST_UPDATE_RENDER_DATA = POST_UPDATE_RENDER_DATA;
RenderFlow.FLAG_POST_RENDER = POST_RENDER;
RenderFlow.FLAG_FINAL = FINAL;
-module.exports = cc.RenderFlow = RenderFlow;
\ No newline at end of file
+module.exports = cc.RenderFlow = RenderFlow;
diff --git a/cocos2d/core/renderer/utils/dynamic-atlas/atlas.js b/cocos2d/core/renderer/utils/dynamic-atlas/atlas.js
index 00f65b60daa..e6b990aa56b 100644
--- a/cocos2d/core/renderer/utils/dynamic-atlas/atlas.js
+++ b/cocos2d/core/renderer/utils/dynamic-atlas/atlas.js
@@ -1,7 +1,9 @@
+const RenderTexture = require('../../../assets/CCRenderTexture');
+
const space = 2;
function Atlas (width, height) {
- let texture = new cc.RenderTexture();
+ let texture = new RenderTexture();
texture.initWithSize(width, height);
texture.update();
@@ -16,8 +18,12 @@ function Atlas (width, height) {
this._innerTextureInfos = {};
this._innerSpriteFrames = [];
+
+ this._count = 0;
}
+Atlas.DEFAULT_HASH = (new RenderTexture())._getHash();
+
cc.js.mixin(Atlas.prototype, {
insertSpriteFrame (spriteFrame) {
let rect = spriteFrame._rect,
@@ -27,8 +33,8 @@ cc.js.mixin(Atlas.prototype, {
let sx = rect.x, sy = rect.y;
if (info) {
- rect.x += info.x;
- rect.y += info.y;
+ sx += info.x;
+ sy += info.y;
}
else {
let width = texture.width, height = texture.height;
@@ -38,19 +44,30 @@ cc.js.mixin(Atlas.prototype, {
this._y = this._nexty;
}
- if ((this._y + height) > this._nexty) {
+ if ((this._y + height + space) > this._nexty) {
this._nexty = this._y + height + space;
}
if (this._nexty > this._height) {
- return false;
+ return null;
}
// texture bleeding
- this._texture.drawTextureAt(texture, this._x-1, this._y);
- this._texture.drawTextureAt(texture, this._x+1, this._y);
- this._texture.drawTextureAt(texture, this._x, this._y-1);
- this._texture.drawTextureAt(texture, this._x, this._y+1);
+ if (cc.dynamicAtlasManager.textureBleeding) {
+ // Smaller frame is more likely to be affected by linear filter
+ if (width <= 8 || height <= 8) {
+ this._texture.drawTextureAt(texture, this._x-1, this._y-1);
+ this._texture.drawTextureAt(texture, this._x-1, this._y+1);
+ this._texture.drawTextureAt(texture, this._x+1, this._y-1);
+ this._texture.drawTextureAt(texture, this._x+1, this._y+1);
+ }
+
+ this._texture.drawTextureAt(texture, this._x-1, this._y);
+ this._texture.drawTextureAt(texture, this._x+1, this._y);
+ this._texture.drawTextureAt(texture, this._x, this._y-1);
+ this._texture.drawTextureAt(texture, this._x, this._y+1);
+ }
+
this._texture.drawTextureAt(texture, this._x, this._y);
this._innerTextureInfos[texture._id] = {
@@ -59,26 +76,25 @@ cc.js.mixin(Atlas.prototype, {
texture: texture
};
- rect.x += this._x;
- rect.y += this._y;
+ this._count++;
+
+ sx += this._x;
+ sy += this._y;
this._x += width + space;
this._dirty = true;
}
- spriteFrame._original = {
+ let frame = {
x: sx,
y: sy,
- texture: spriteFrame._texture
+ texture: this._texture
}
-
- spriteFrame._texture = this._texture;
- spriteFrame._calculateUV();
-
+
this._innerSpriteFrames.push(spriteFrame);
- return true;
+ return frame;
},
update () {
@@ -87,6 +103,17 @@ cc.js.mixin(Atlas.prototype, {
this._dirty = false;
},
+ deleteInnerTexture (texture) {
+ if (texture && this._innerTextureInfos[texture._id]) {
+ delete this._innerTextureInfos[texture._id];
+ this._count--;
+ }
+ },
+
+ isEmpty () {
+ return this._count <= 0;
+ },
+
reset () {
this._x = space;
this._y = space;
@@ -98,12 +125,7 @@ cc.js.mixin(Atlas.prototype, {
if (!frame.isValid) {
continue;
}
- let oriInfo = frame._original;
- frame._rect.x = oriInfo.x;
- frame._rect.y = oriInfo.y;
- frame._texture = oriInfo.texture;
- frame._calculateUV();
- frame._original = null;
+ frame._resetDynamicAtlasFrame();
}
this._innerSpriteFrames.length = 0;
this._innerTextureInfos = {};
diff --git a/cocos2d/core/renderer/utils/dynamic-atlas/manager.js b/cocos2d/core/renderer/utils/dynamic-atlas/manager.js
index 291f46234b5..c88cfed1a5c 100644
--- a/cocos2d/core/renderer/utils/dynamic-atlas/manager.js
+++ b/cocos2d/core/renderer/utils/dynamic-atlas/manager.js
@@ -5,10 +5,8 @@ let _atlasIndex = -1;
let _maxAtlasCount = 5;
let _textureSize = 2048;
-// Smaller frame is more likely to be affected by linear filter
-let _minFrameSize = 8;
let _maxFrameSize = 512;
-
+let _textureBleeding = true;
let _debugNode = null;
@@ -28,15 +26,16 @@ function beforeSceneLoad () {
let _enabled = false;
/**
- * !#en Manager the dynamic atlas.
- * !#zh 管理动态图集。
+ * !#en Manage Dynamic Atlas Manager. Dynamic Atlas Manager is used for merging textures at runtime, see [Dynamic Atlas](https://docs.cocos.com/creator/manual/en/advanced-topics/dynamic-atlas.html) for details.
+ * !#zh 管理动态图集。动态图集用于在运行时对贴图进行合并,详见 [动态合图](https://docs.cocos.com/creator/manual/zh/advanced-topics/dynamic-atlas.html)。
* @class DynamicAtlasManager
*/
let dynamicAtlasManager = {
+ Atlas: Atlas,
/**
- * !#en Enabled or Disabled dynamic atlas.
- * !#zh 开启或者关闭动态图集。
+ * !#en Enable or disable the dynamic atlas, see [Dynamic Atlas](https://docs.cocos.com/creator/manual/en/advanced-topics/dynamic-atlas.html) for details.
+ * !#zh 开启或者关闭动态图集,详见 [动态合图](https://docs.cocos.com/creator/manual/zh/advanced-topics/dynamic-atlas.html)。
* @property enabled
* @type {Boolean}
*/
@@ -70,6 +69,20 @@ let dynamicAtlasManager = {
_maxAtlasCount = value;
},
+ /**
+ * !#en Is enable textureBleeding.
+ * !#zh 是否开启 textureBleeding
+ * @property textureBleeding
+ * @type {Boolean}
+ */
+ get textureBleeding () {
+ return _textureBleeding;
+ },
+
+ set textureBleeding (enable) {
+ _textureBleeding = enable;
+ },
+
/**
* !#en The size of the atlas that was created
* !#zh 创建的图集的宽高
@@ -96,6 +109,14 @@ let dynamicAtlasManager = {
_maxFrameSize = value;
},
+ /**
+ * !#en The minimum size of the picture that can be added to the atlas.
+ * !#zh 可以添加进图集的图片的最小尺寸。
+ * @property minFrameSize
+ * @type {Number}
+ * @deprecated
+ */
+
/**
* !#en Append a sprite frame into the dynamic atlas.
* !#zh 添加碎图进入动态图集。
@@ -103,29 +124,23 @@ let dynamicAtlasManager = {
* @param {SpriteFrame} spriteFrame
*/
insertSpriteFrame (spriteFrame) {
- if (CC_EDITOR) return;
+ if (CC_EDITOR) return null;
if (!_enabled || _atlasIndex === _maxAtlasCount ||
- !spriteFrame || spriteFrame._original) return;
+ !spriteFrame || spriteFrame._original) return null;
- let texture = spriteFrame._texture;
- if (texture instanceof cc.RenderTexture || cc.Texture2D._isCompressed(texture)) return;
-
- let w = texture.width, h = texture.height;
- let min = texture._minFilter, mag = texture._magFilter;
- let LINEAR = cc.Texture2D.Filter.LINEAR;
- if (w > _maxFrameSize || h > _maxFrameSize || w <= _minFrameSize || h <= _minFrameSize || (min & mag) !== LINEAR) {
- return;
- }
+ if (!spriteFrame._texture.packable) return null;
let atlas = _atlases[_atlasIndex];
if (!atlas) {
atlas = newAtlas();
}
- if (!atlas.insertSpriteFrame(spriteFrame) && _atlasIndex !== _maxAtlasCount) {
+ let frame = atlas.insertSpriteFrame(spriteFrame);
+ if (!frame && _atlasIndex !== _maxAtlasCount) {
atlas = newAtlas();
- atlas.insertSpriteFrame(spriteFrame);
+ return atlas.insertSpriteFrame(spriteFrame);
}
+ return frame;
},
/**
@@ -141,13 +156,35 @@ let dynamicAtlasManager = {
_atlasIndex = -1;
},
+ deleteAtlasSpriteFrame (spriteFrame) {
+ if (!spriteFrame._original) return;
+
+ let texture = spriteFrame._original._texture;
+ this.deleteAtlasTexture(texture);
+ },
+
+ deleteAtlasTexture (texture) {
+ if (texture) {
+ for (let i = _atlases.length - 1; i >= 0; i--) {
+ _atlases[i].deleteInnerTexture(texture);
+
+ if (_atlases[i].isEmpty()) {
+ _atlases[i].destroy();
+ _atlases.splice(i, 1);
+ _atlasIndex--;
+ }
+ }
+ }
+ },
+
/**
* !#en Displays all the dynamic atlas in the current scene, which you can use to view the current atlas state.
* !#zh 在当前场景中显示所有动态图集,可以用来查看当前的合图状态。
* @method showDebug
* @param {Boolean} show
+ * @return {Node}
*/
- showDebug: CC_DEV && function (show) {
+ showDebug: CC_DEBUG && function (show) {
if (show) {
if (!_debugNode || !_debugNode.isValid) {
let width = cc.visibleRect.width;
@@ -158,7 +195,7 @@ let dynamicAtlasManager = {
_debugNode.height = height;
_debugNode.x = width/2;
_debugNode.y = height/2;
- _debugNode._zIndex = cc.macro.MAX_ZINDEX;
+ _debugNode.zIndex = cc.macro.MAX_ZINDEX;
_debugNode.parent = cc.director.getScene();
_debugNode.groupIndex = cc.Node.BuiltinGroupIndex.DEBUG;
@@ -184,12 +221,13 @@ let dynamicAtlasManager = {
let spriteFrame = new cc.SpriteFrame();
spriteFrame.setTexture(_atlases[i]._texture);
- let sprite = node.addComponent(cc.Sprite)
+ let sprite = node.addComponent(cc.Sprite);
sprite.spriteFrame = spriteFrame;
node.parent = content;
}
}
+ return _debugNode;
}
else {
if (_debugNode) {
diff --git a/cocos2d/core/renderer/utils/label/bmfont.js b/cocos2d/core/renderer/utils/label/bmfont.js
index e05fad174de..0b91a2745ce 100644
--- a/cocos2d/core/renderer/utils/label/bmfont.js
+++ b/cocos2d/core/renderer/utils/label/bmfont.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -23,78 +23,22 @@
THE SOFTWARE.
****************************************************************************/
-const macro = require('../../../platform/CCMacro');
+import Assembler2D from '../../assembler-2d';
+const textUtils = require('../../../utils/text-utils');
+const macro = require('../../../platform/CCMacro');
const Label = require('../../../components/CCLabel');
const Overflow = Label.Overflow;
-const textUtils = require('../../../utils/text-utils');
-
-let FontLetterDefinition = function() {
- this._u = 0;
- this._v = 0;
- this._width = 0;
- this._height = 0;
- this._offsetX = 0;
- this._offsetY = 0;
- this._textureID = 0;
- this._validDefinition = false;
- this._xAdvance = 0;
-};
-
-cc.FontAtlas = function (fntConfig) {
- this._letterDefinitions = {};
-};
-
-cc.FontAtlas.prototype = {
- constructor: cc.FontAtlas,
- addLetterDefinitions: function(letter, letterDefinition) {
- this._letterDefinitions[letter] = letterDefinition;
- },
- cloneLetterDefinition: function() {
- let copyLetterDefinitions = {};
- for (let key in this._letterDefinitions) {
- let value = new FontLetterDefinition();
- cc.js.mixin(value, this._letterDefinitions[key]);
- copyLetterDefinitions[key] = value;
- }
- return copyLetterDefinitions;
- },
- assignLetterDefinitions: function(letterDefinition) {
- for (let key in this._letterDefinitions) {
- let newValue = letterDefinition[key];
- let oldValue = this._letterDefinitions[key];
- cc.js.mixin(oldValue, newValue);
- }
- },
- scaleFontLetterDefinition: function(scaleFactor) {
- for (let fontDefinition in this._letterDefinitions) {
- let letterDefinitions = this._letterDefinitions[fontDefinition];
- letterDefinitions._width *= scaleFactor;
- letterDefinitions._height *= scaleFactor;
- letterDefinitions._offsetX *= scaleFactor;
- letterDefinitions._offsetY *= scaleFactor;
- letterDefinitions._xAdvance *= scaleFactor;
- }
- },
- getLetterDefinitionForChar: function(char) {
- let hasKey = this._letterDefinitions.hasOwnProperty(char.charCodeAt(0));
- let letterDefinition;
- if (hasKey) {
- letterDefinition = this._letterDefinitions[char.charCodeAt(0)];
- } else {
- letterDefinition = null;
- }
- return letterDefinition;
- }
-};
+const shareLabelInfo = require('../utils').shareLabelInfo;
let LetterInfo = function() {
- this._char = '';
- this._valid = true;
- this._positionX = 0;
- this._positionY = 0;
- this._lineIndex = 0;
+ this.char = '';
+ this.valid = true;
+ this.x = 0;
+ this.y = 0;
+ this.line = 0;
+ this.hash = "";
};
let _tmpRect = cc.rect();
@@ -105,23 +49,23 @@ let _horizontalKernings = [];
let _lettersInfo = [];
let _linesWidth = [];
let _linesOffsetX = [];
-let _labelDimensions = cc.size();
-let _fontAtlas = null;
let _fntConfig = null;
let _numberOfLines = 0;
let _textDesiredHeight = 0;
let _letterOffsetY = 0;
let _tailoredTopY = 0;
+
let _tailoredBottomY = 0;
let _bmfontScale = 1.0;
+
let _lineBreakWithoutSpaces = false;
let _spriteFrame = null;
let _lineSpacing = 0;
+let _contentSize = cc.size();
let _string = '';
let _fontSize = 0;
let _originFontSize = 0;
-let _contentSize = cc.size();
let _hAlign = 0;
let _vAlign = 0;
let _spacingX = 0;
@@ -132,121 +76,118 @@ let _labelWidth = 0;
let _labelHeight = 0;
let _maxLineWidth = 0;
-module.exports = {
+export default class BmfontAssembler extends Assembler2D {
updateRenderData (comp) {
- if (!comp._renderData.vertDirty) return;
+ if (!comp._vertsDirty) return;
if (_comp === comp) return;
_comp = comp;
- this._updateProperties();
+ this._reserveQuads(comp, comp.string.toString().length);
+ this._updateFontFamily(comp);
+ this._updateProperties(comp);
+ this._updateLabelInfo(comp);
this._updateContent();
+ this.updateWorldVerts(comp);
_comp._actualFontSize = _fontSize;
_comp.node.setContentSize(_contentSize);
- _comp._renderData.vertDirty = _comp._renderData.uvDirty = false;
-
+ _comp._vertsDirty = false;
_comp = null;
-
this._resetProperties();
- },
+ }
_updateFontScale () {
_bmfontScale = _fontSize / _originFontSize;
- },
+ }
- _updateProperties () {
- let fontAsset = _comp.font;
+ _updateFontFamily (comp) {
+ let fontAsset = comp.font;
_spriteFrame = fontAsset.spriteFrame;
_fntConfig = fontAsset._fntConfig;
+ shareLabelInfo.fontAtlas = fontAsset._fontDefDictionary;
- _fontAtlas = _comp._fontAtlas;
- if (!_fontAtlas) {
- _fontAtlas = new cc.FontAtlas(_fntConfig);
-
- let fontDict = _fntConfig.fontDefDictionary;
-
- for (let fontDef in fontDict) {
- let letterDefinition = new FontLetterDefinition();
-
- let rect = fontDict[fontDef].rect;
-
- letterDefinition._offsetX = fontDict[fontDef].xOffset;
- letterDefinition._offsetY = fontDict[fontDef].yOffset;
- letterDefinition._width = rect.width;
- letterDefinition._height = rect.height;
- letterDefinition._u = rect.x;
- letterDefinition._v = rect.y;
- //FIXME: only one texture supported for now
- letterDefinition._textureID = 0;
- letterDefinition._validDefinition = true;
- letterDefinition._xAdvance = fontDict[fontDef].xAdvance;
+ this.packToDynamicAtlas(comp, _spriteFrame);
+ }
- _fontAtlas.addLetterDefinitions(fontDef, letterDefinition);
- }
+ _updateLabelInfo() {
+ // clear
+ shareLabelInfo.hash = "";
+ shareLabelInfo.margin = 0;
+ }
- _comp._fontAtlas = _fontAtlas;
- }
+ _updateProperties (comp) {
+ _string = comp.string.toString();
+ _fontSize = comp.fontSize;
+ _originFontSize = _fntConfig ? _fntConfig.fontSize : comp.fontSize;
+ _hAlign = comp.horizontalAlign;
+ _vAlign = comp.verticalAlign;
+ _spacingX = comp.spacingX;
+ _overflow = comp.overflow;
+ _lineHeight = comp._lineHeight;
+
+ _contentSize.width = comp.node.width;
+ _contentSize.height = comp.node.height;
- _string = _comp.string.toString();
- _fontSize = _comp.fontSize;
- _originFontSize = _fntConfig.fontSize;
- _contentSize.width = _comp.node._contentSize.width;
- _contentSize.height = _comp.node._contentSize.height;
- _hAlign = _comp.horizontalAlign;
- _vAlign = _comp.verticalAlign;
- _spacingX = _comp.spacingX;
- _overflow = _comp.overflow;
- _lineHeight = _comp._lineHeight;
-
// should wrap text
if (_overflow === Overflow.NONE) {
_isWrapText = false;
+ _contentSize.width += shareLabelInfo.margin * 2;
+ _contentSize.height += shareLabelInfo.margin * 2;
}
else if (_overflow === Overflow.RESIZE_HEIGHT) {
_isWrapText = true;
+ _contentSize.height += shareLabelInfo.margin * 2;
}
else {
- _isWrapText = _comp.enableWrapText;
+ _isWrapText = comp.enableWrapText;
}
+
+ shareLabelInfo.lineHeight = _lineHeight;
+ shareLabelInfo.fontSize = _fontSize;
this._setupBMFontOverflowMetrics();
- },
+ }
_resetProperties () {
- _fontAtlas = null;
_fntConfig = null;
_spriteFrame = null;
- },
+ shareLabelInfo.hash = "";
+ shareLabelInfo.margin = 0;
+ }
_updateContent () {
this._updateFontScale();
this._computeHorizontalKerningForText();
this._alignText();
- },
+ }
_computeHorizontalKerningForText () {
let string = _string;
let stringLen = string.length;
- let kerningDict = _fntConfig.kerningDict;
let horizontalKernings = _horizontalKernings;
-
- let prev = -1;
- for (let i = 0; i < stringLen; ++i) {
- let key = string.charCodeAt(i);
- let kerningAmount = kerningDict[(prev << 16) | (key & 0xffff)] || 0;
- if (i < stringLen - 1) {
- horizontalKernings[i] = kerningAmount;
- } else {
- horizontalKernings[i] = 0;
+ let kerningDict;
+ _fntConfig && (kerningDict = _fntConfig.kerningDict);
+ if (kerningDict && !cc.js.isEmptyObject(kerningDict)) {
+ let prev = -1;
+ for (let i = 0; i < stringLen; ++i) {
+ let key = string.charCodeAt(i);
+ let kerningAmount = kerningDict[(prev << 16) | (key & 0xffff)] || 0;
+ if (i < stringLen - 1) {
+ horizontalKernings[i] = kerningAmount;
+ } else {
+ horizontalKernings[i] = 0;
+ }
+ prev = key;
}
- prev = key;
+ } else {
+ horizontalKernings.length = 0;
}
- },
+ }
- _multilineTextWrap: function(nextTokenFunc) {
+ _multilineTextWrap (nextTokenFunc) {
let textLen = _string.length;
let lineIndex = 0;
@@ -260,10 +201,6 @@ module.exports = {
let letterDef = null;
let letterPosition = cc.v2(0, 0);
- this._updateFontScale();
-
- let letterDefinitions = _fontAtlas._letterDefinitions;
-
for (let index = 0; index < textLen;) {
let character = _string.charAt(index);
if (character === "\n") {
@@ -271,7 +208,7 @@ module.exports = {
letterRight = 0;
lineIndex++;
nextTokenX = 0;
- nextTokenY -= _lineHeight * _bmfontScale + _lineSpacing;
+ nextTokenY -= _lineHeight * this._getFontScale() + _lineSpacing;
this._recordPlaceholderInfo(index, character);
index++;
continue;
@@ -291,48 +228,50 @@ module.exports = {
this._recordPlaceholderInfo(letterIndex, character);
continue;
}
- letterDef = _fontAtlas.getLetterDefinitionForChar(character);
+ letterDef = shareLabelInfo.fontAtlas.getLetterDefinitionForChar(character, shareLabelInfo);
if (!letterDef) {
this._recordPlaceholderInfo(letterIndex, character);
- console.log("Can't find letter definition in texture atlas " + _fntConfig.atlasName + " for letter:" + character);
+ let atlasName = "";
+ _fntConfig && (atlasName = _fntConfig.atlasName);
+ console.log("Can't find letter definition in texture atlas " + atlasName + " for letter:" + character);
continue;
}
- let letterX = nextLetterX + letterDef._offsetX * _bmfontScale;
+ let letterX = nextLetterX + letterDef.offsetX * _bmfontScale - shareLabelInfo.margin;
if (_isWrapText
&& _maxLineWidth > 0
&& nextTokenX > 0
- && letterX + letterDef._width * _bmfontScale > _maxLineWidth
+ && letterX + letterDef.w * _bmfontScale > _maxLineWidth
&& !textUtils.isUnicodeSpace(character)) {
_linesWidth.push(letterRight);
letterRight = 0;
lineIndex++;
nextTokenX = 0;
- nextTokenY -= (_lineHeight * _bmfontScale + _lineSpacing);
+ nextTokenY -= (_lineHeight * this._getFontScale() + _lineSpacing);
newLine = true;
break;
} else {
letterPosition.x = letterX;
}
- letterPosition.y = nextTokenY - letterDef._offsetY * _bmfontScale;
- this._recordLetterInfo(letterDefinitions, letterPosition, character, letterIndex, lineIndex);
+ letterPosition.y = nextTokenY - letterDef.offsetY * _bmfontScale + shareLabelInfo.margin;
+ this._recordLetterInfo(letterPosition, character, letterIndex, lineIndex);
if (letterIndex + 1 < _horizontalKernings.length && letterIndex < textLen - 1) {
nextLetterX += _horizontalKernings[letterIndex + 1];
}
- nextLetterX += letterDef._xAdvance * _bmfontScale + _spacingX;
+ nextLetterX += letterDef.xAdvance * _bmfontScale + _spacingX - shareLabelInfo.margin * 2;
- tokenRight = letterPosition.x + letterDef._width * _bmfontScale;
+ tokenRight = letterPosition.x + letterDef.w * _bmfontScale - shareLabelInfo.margin;
if (tokenHighestY < letterPosition.y) {
tokenHighestY = letterPosition.y;
}
- if (tokenLowestY > letterPosition.y - letterDef._height * _bmfontScale) {
- tokenLowestY = letterPosition.y - letterDef._height * _bmfontScale;
+ if (tokenLowestY > letterPosition.y - letterDef.h * _bmfontScale) {
+ tokenLowestY = letterPosition.y - letterDef.h * _bmfontScale;
}
} //end of for loop
@@ -358,7 +297,7 @@ module.exports = {
_linesWidth.push(letterRight);
_numberOfLines = lineIndex + 1;
- _textDesiredHeight = _numberOfLines * _lineHeight * _bmfontScale;
+ _textDesiredHeight = _numberOfLines * _lineHeight * this._getFontScale();
if (_numberOfLines > 1) {
_textDesiredHeight += (_numberOfLines - 1) * _lineSpacing;
}
@@ -366,29 +305,37 @@ module.exports = {
_contentSize.width = _labelWidth;
_contentSize.height = _labelHeight;
if (_labelWidth <= 0) {
- _contentSize.width = parseFloat(longestLine.toFixed(2));
+ _contentSize.width = parseFloat(longestLine.toFixed(2)) + shareLabelInfo.margin * 2;
}
if (_labelHeight <= 0) {
- _contentSize.height = parseFloat(_textDesiredHeight.toFixed(2));
+ _contentSize.height = parseFloat(_textDesiredHeight.toFixed(2)) + shareLabelInfo.margin * 2;
}
_tailoredTopY = _contentSize.height;
_tailoredBottomY = 0;
- if (highestY > 0) {
- _tailoredTopY = _contentSize.height + highestY;
- }
- if (lowestY < -_textDesiredHeight) {
- _tailoredBottomY = _textDesiredHeight + lowestY;
+
+ if (_overflow !== Overflow.CLAMP) {
+ if (highestY > 0) {
+ _tailoredTopY = _contentSize.height + highestY;
+ }
+
+ if (lowestY < -_textDesiredHeight) {
+ _tailoredBottomY = _textDesiredHeight + lowestY;
+ }
}
return true;
- },
+ }
- _getFirstCharLen: function() {
+ _getFirstCharLen () {
return 1;
- },
+ }
+
+ _getFontScale () {
+ return _overflow === Overflow.SHRINK ? _bmfontScale : 1;
+ }
- _getFirstWordLen: function(text, startIndex, textLen) {
+ _getFirstWordLen (text, startIndex, textLen) {
let character = text.charAt(startIndex);
if (textUtils.isUnicodeCJK(character)
|| character === "\n"
@@ -397,27 +344,27 @@ module.exports = {
}
let len = 1;
- let letterDef = _fontAtlas.getLetterDefinitionForChar(character);
+ let letterDef = shareLabelInfo.fontAtlas.getLetterDefinitionForChar(character, shareLabelInfo);
if (!letterDef) {
return len;
}
- let nextLetterX = letterDef._xAdvance * _bmfontScale + _spacingX;
+ let nextLetterX = letterDef.xAdvance * _bmfontScale + _spacingX;
let letterX;
for (let index = startIndex + 1; index < textLen; ++index) {
character = text.charAt(index);
- letterDef = _fontAtlas.getLetterDefinitionForChar(character);
+ letterDef = shareLabelInfo.fontAtlas.getLetterDefinitionForChar(character, shareLabelInfo);
if (!letterDef) {
break;
}
- letterX = nextLetterX + letterDef._offsetX * _bmfontScale;
+ letterX = nextLetterX + letterDef.offsetX * _bmfontScale;
- if(letterX + letterDef._width * _bmfontScale > _maxLineWidth
+ if(letterX + letterDef.w * _bmfontScale > _maxLineWidth
&& !textUtils.isUnicodeSpace(character)
&& _maxLineWidth > 0) {
return len;
}
- nextLetterX += letterDef._xAdvance * _bmfontScale + _spacingX;
+ nextLetterX += letterDef.xAdvance * _bmfontScale + _spacingX;
if (character === "\n"
|| textUtils.isUnicodeSpace(character)
|| textUtils.isUnicodeCJK(character)) {
@@ -427,41 +374,44 @@ module.exports = {
}
return len;
- },
+ }
- _multilineTextWrapByWord: function() {
+ _multilineTextWrapByWord () {
return this._multilineTextWrap(this._getFirstWordLen);
- },
+ }
- _multilineTextWrapByChar: function() {
+ _multilineTextWrapByChar () {
return this._multilineTextWrap(this._getFirstCharLen);
- },
+ }
- _recordPlaceholderInfo: function(letterIndex, char) {
+ _recordPlaceholderInfo (letterIndex, char) {
if (letterIndex >= _lettersInfo.length) {
let tmpInfo = new LetterInfo();
_lettersInfo.push(tmpInfo);
}
- _lettersInfo[letterIndex]._char = char;
- _lettersInfo[letterIndex]._valid = false;
- },
+ _lettersInfo[letterIndex].char = char;
+ _lettersInfo[letterIndex].hash = char.charCodeAt(0) + shareLabelInfo.hash;
+ _lettersInfo[letterIndex].valid = false;
+ }
- _recordLetterInfo: function(letterDefinitions, letterPosition, character, letterIndex, lineIndex) {
+ _recordLetterInfo (letterPosition, character, letterIndex, lineIndex) {
if (letterIndex >= _lettersInfo.length) {
let tmpInfo = new LetterInfo();
_lettersInfo.push(tmpInfo);
}
- character = character.charCodeAt(0);
+ let char = character.charCodeAt(0);
+ let key = char + shareLabelInfo.hash;
- _lettersInfo[letterIndex]._lineIndex = lineIndex;
- _lettersInfo[letterIndex]._char = character;
- _lettersInfo[letterIndex]._valid = letterDefinitions[character]._validDefinition;
- _lettersInfo[letterIndex]._positionX = letterPosition.x;
- _lettersInfo[letterIndex]._positionY = letterPosition.y;
- },
+ _lettersInfo[letterIndex].line= lineIndex;
+ _lettersInfo[letterIndex].char = character;
+ _lettersInfo[letterIndex].hash = key;
+ _lettersInfo[letterIndex].valid = shareLabelInfo.fontAtlas.getLetter(key).valid;
+ _lettersInfo[letterIndex].x = letterPosition.x;
+ _lettersInfo[letterIndex].y = letterPosition.y;
+ }
- _alignText: function() {
+ _alignText () {
_textDesiredHeight = 0;
_linesWidth.length = 0;
@@ -485,7 +435,7 @@ module.exports = {
this._shrinkLabelToContentSize(this._isHorizontalClamp);
}
}
- },
+ }
_scaleFontSizeDown (fontSize) {
let shouldUpdateContent = true;
@@ -498,47 +448,41 @@ module.exports = {
if (shouldUpdateContent) {
this._updateContent();
}
- },
+ }
_shrinkLabelToContentSize (lambda) {
let fontSize = _fontSize;
- let originalLineHeight = _lineHeight;
- let fontAtlas = _fontAtlas;
-
- let i = 0;
- let tempLetterDefinition = fontAtlas.cloneLetterDefinition();
- let flag = true;
- while (lambda()) {
- ++i;
+ let left = 0, right = fontSize | 0, mid = 0;
+ while (left < right) {
+ mid = (left + right + 1) >> 1;
- let newFontSize = fontSize - i;
- flag = false;
+ let newFontSize = mid;
if (newFontSize <= 0) {
break;
}
- let scale = newFontSize / fontSize;
- fontAtlas.assignLetterDefinitions(tempLetterDefinition);
- fontAtlas.scaleFontLetterDefinition(scale);
- _lineHeight = originalLineHeight * scale;
+ _bmfontScale = newFontSize / _originFontSize;
+
if (!_lineBreakWithoutSpaces) {
this._multilineTextWrapByWord();
} else {
this._multilineTextWrapByChar();
}
this._computeAlignmentOffset();
- }
-
- _lineHeight = originalLineHeight;
- fontAtlas.assignLetterDefinitions(tempLetterDefinition);
- if (!flag) {
- if (fontSize - i >= 0) {
- this._scaleFontSizeDown(fontSize - i);
+ if (lambda()) {
+ right = mid - 1;
+ } else {
+ left = mid;
}
}
- },
+
+ let actualFontSize = left;
+ if (actualFontSize >= 0) {
+ this._scaleFontSizeDown(actualFontSize);
+ }
+ }
_isVerticalClamp () {
if (_textDesiredHeight > _contentSize.height) {
@@ -546,18 +490,17 @@ module.exports = {
} else {
return false;
}
- },
+ }
_isHorizontalClamp () {
- let letterDefinitions = _fontAtlas._letterDefinitions;
let letterClamp = false;
for (let ctr = 0, l = _string.length; ctr < l; ++ctr) {
let letterInfo = _lettersInfo[ctr];
- if (letterInfo._valid) {
- let letterDef = letterDefinitions[letterInfo._char];
+ if (letterInfo.valid) {
+ let letterDef = shareLabelInfo.fontAtlas.getLetter(letterInfo.hash);
- let px = letterInfo._positionX + letterDef._width / 2 * _bmfontScale;
- let lineIndex = letterInfo._lineIndex;
+ let px = letterInfo.x + letterDef.w * _bmfontScale;
+ let lineIndex = letterInfo.line;
if (_labelWidth > 0) {
if (!_isWrapText) {
if(px > _contentSize.width){
@@ -576,7 +519,7 @@ module.exports = {
}
return letterClamp;
- },
+ }
_isHorizontalClamped (px, lineIndex) {
let wordWidth = _linesWidth[lineIndex];
@@ -587,16 +530,17 @@ module.exports = {
}else{
return (wordWidth > _contentSize.width && letterOverClamp);
}
- },
+ }
_updateQuads () {
- let letterDefinitions = _fontAtlas._letterDefinitions;
-
- let texture = _spriteFrame._texture;
+ let texture = _spriteFrame ? _spriteFrame._texture : shareLabelInfo.fontAtlas.getTexture();
let node = _comp.node;
- let renderData = _comp._renderData;
- renderData.dataLength = renderData.vertexCount = renderData.indiceCount = 0;
+
+ this.verticesCount = this.indicesCount = 0;
+
+ // Need to reset dataLength in Canvas rendering mode.
+ this._renderData && (this._renderData.dataLength = 0);
let contentSize = _contentSize,
appx = node._anchorPoint.x * contentSize.width,
@@ -605,15 +549,15 @@ module.exports = {
let ret = true;
for (let ctr = 0, l = _string.length; ctr < l; ++ctr) {
let letterInfo = _lettersInfo[ctr];
- if (!letterInfo._valid) continue;
- let letterDef = letterDefinitions[letterInfo._char];
+ if (!letterInfo.valid) continue;
+ let letterDef = shareLabelInfo.fontAtlas.getLetter(letterInfo.hash);
- _tmpRect.height = letterDef._height;
- _tmpRect.width = letterDef._width;
- _tmpRect.x = letterDef._u;
- _tmpRect.y = letterDef._v;
+ _tmpRect.height = letterDef.h;
+ _tmpRect.width = letterDef.w;
+ _tmpRect.x = letterDef.u;
+ _tmpRect.y = letterDef.v;
- let py = letterInfo._positionY + _letterOffsetY;
+ let py = letterInfo.y + _letterOffsetY;
if (_labelHeight > 0) {
if (py > _tailoredTopY) {
@@ -623,20 +567,20 @@ module.exports = {
py = py - clipTop;
}
- if (py - letterDef._height * _bmfontScale < _tailoredBottomY) {
- _tmpRect.height = (py < _tailoredBottomY) ? 0 : (py - _tailoredBottomY);
+ if ((py - letterDef.h * _bmfontScale < _tailoredBottomY) && _overflow === Overflow.CLAMP) {
+ _tmpRect.height = (py < _tailoredBottomY) ? 0 : (py - _tailoredBottomY) / _bmfontScale;
}
}
- let lineIndex = letterInfo._lineIndex;
- let px = letterInfo._positionX + letterDef._width / 2 * _bmfontScale + _linesOffsetX[lineIndex];
+ let lineIndex = letterInfo.line;
+ let px = letterInfo.x + letterDef.w / 2 * _bmfontScale + _linesOffsetX[lineIndex];
if (_labelWidth > 0) {
if (this._isHorizontalClamped(px, lineIndex)) {
if (_overflow === Overflow.CLAMP) {
_tmpRect.width = 0;
} else if (_overflow === Overflow.SHRINK) {
- if (_contentSize.width > letterDef._width) {
+ if (_contentSize.width > letterDef.w) {
ret = false;
break;
} else {
@@ -647,38 +591,41 @@ module.exports = {
}
if (_tmpRect.height > 0 && _tmpRect.width > 0) {
- let isRotated = _spriteFrame.isRotated();
+ let isRotated = this._determineRect(_tmpRect);
+ let letterPositionX = letterInfo.x + _linesOffsetX[letterInfo.line];
+ this.appendQuad(_comp, texture, _tmpRect, isRotated, letterPositionX - appx, py - appy, _bmfontScale);
+ }
+ }
+ this._quadsUpdated(_comp);
- let originalSize = _spriteFrame._originalSize;
- let rect = _spriteFrame._rect;
- let offset = _spriteFrame._offset;
- let trimmedLeft = offset.x + (originalSize.width - rect.width) / 2;
- let trimmedTop = offset.y - (originalSize.height - rect.height) / 2;
+ return ret;
+ }
- if(!isRotated) {
- _tmpRect.x += (rect.x - trimmedLeft);
- _tmpRect.y += (rect.y + trimmedTop);
- } else {
- let originalX = _tmpRect.x;
- _tmpRect.x = rect.x + rect.height - _tmpRect.y - _tmpRect.height - trimmedTop;
- _tmpRect.y = originalX + rect.y - trimmedLeft;
- if (_tmpRect.y < 0) {
- _tmpRect.height = _tmpRect.height + trimmedTop;
- }
- }
+ _determineRect (tempRect) {
+ let isRotated = _spriteFrame.isRotated();
+
+ let originalSize = _spriteFrame._originalSize;
+ let rect = _spriteFrame._rect;
+ let offset = _spriteFrame._offset;
+ let trimmedLeft = offset.x + (originalSize.width - rect.width) / 2;
+ let trimmedTop = offset.y - (originalSize.height - rect.height) / 2;
- let letterPositionX = letterInfo._positionX + _linesOffsetX[letterInfo._lineIndex];
- this.appendQuad(renderData, texture, _tmpRect, isRotated, letterPositionX - appx, py - appy, _bmfontScale);
+ if(!isRotated) {
+ tempRect.x += (rect.x - trimmedLeft);
+ tempRect.y += (rect.y + trimmedTop);
+ } else {
+ let originalX = tempRect.x;
+ tempRect.x = rect.x + rect.height - tempRect.y - tempRect.height - trimmedTop;
+ tempRect.y = originalX + rect.y - trimmedLeft;
+ if (tempRect.y < 0) {
+ tempRect.height = tempRect.height + trimmedTop;
}
}
- return ret;
- },
-
- appendQuad (renderData, texture, rect, rotated, x, y, scale) {
- },
+ return isRotated;
+ }
- _computeAlignmentOffset: function() {
+ _computeAlignmentOffset () {
_linesOffsetX.length = 0;
switch (_hAlign) {
@@ -701,20 +648,19 @@ module.exports = {
break;
}
- switch (_vAlign) {
- case macro.VerticalTextAlignment.TOP:
- _letterOffsetY = _contentSize.height;
- break;
- case macro.VerticalTextAlignment.CENTER:
- _letterOffsetY = (_contentSize.height + _textDesiredHeight) / 2;
- break;
- case macro.VerticalTextAlignment.BOTTOM:
- _letterOffsetY = _textDesiredHeight;
- break;
- default:
- break;
+ // TOP
+ _letterOffsetY = _contentSize.height;
+ if (_vAlign !== macro.VerticalTextAlignment.TOP) {
+ let blank = _contentSize.height - _textDesiredHeight + _lineHeight * this._getFontScale() - _originFontSize * _bmfontScale;
+ if (_vAlign === macro.VerticalTextAlignment.BOTTOM) {
+ // BOTTOM
+ _letterOffsetY -= blank;
+ } else {
+ // CENTER:
+ _letterOffsetY -= blank / 2;
+ }
}
- },
+ }
_setupBMFontOverflowMetrics () {
let newWidth = _contentSize.width,
@@ -731,8 +677,13 @@ module.exports = {
_labelWidth = newWidth;
_labelHeight = newHeight;
- _labelDimensions.width = newWidth;
- _labelDimensions.height = newHeight;
_maxLineWidth = newWidth;
}
-};
+
+ updateWorldVerts() {}
+
+ appendQuad (comp, texture, rect, rotated, x, y, scale) {}
+ _quadsUpdated (comp) {}
+
+ _reserveQuads () {}
+}
\ No newline at end of file
diff --git a/cocos2d/core/renderer/utils/label/label-frame.js b/cocos2d/core/renderer/utils/label/label-frame.js
new file mode 100644
index 00000000000..ac42c02b59f
--- /dev/null
+++ b/cocos2d/core/renderer/utils/label/label-frame.js
@@ -0,0 +1,118 @@
+/****************************************************************************
+ Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+/**
+ * !#en Class for Label Frame.
+ * !#zh LabelFrame
+ */
+function LabelFrame () {
+ // the location of the label on rendering texture
+ this._rect = null;
+ // uv data of frame
+ this.uv = [];
+ // texture of frame
+ this._texture = null;
+ // store original info before packed to dynamic atlas
+ this._original = null;
+}
+
+LabelFrame.prototype = {
+ constructor: LabelFrame,
+
+ /**
+ * !#en Returns the rect of the label frame in the texture.
+ * !#zh 获取 LabelFrame 的纹理矩形区域
+ * @method getRect
+ * @return {Rect}
+ */
+ getRect: function () {
+ return cc.rect(this._rect);
+ },
+
+ /**
+ * !#en Sets the rect of the label frame in the texture.
+ * !#zh 设置 LabelFrame 的纹理矩形区域
+ * @method setRect
+ * @param {Rect} rect
+ */
+ setRect: function (rect) {
+ this._rect = rect;
+ if (this._texture)
+ this._calculateUV();
+ },
+
+ _setDynamicAtlasFrame (frame) {
+ if (!frame) return;
+
+ this._original = {
+ _texture : this._texture,
+ _x : this._rect.x,
+ _y : this._rect.y
+ }
+
+ this._texture = frame.texture;
+ this._rect.x = frame.x;
+ this._rect.y = frame.y;
+ this._calculateUV();
+ },
+ _resetDynamicAtlasFrame () {
+ if (!this._original) return;
+ this._rect.x = this._original._x;
+ this._rect.y = this._original._y;
+ this._texture = this._original._texture;
+ this._original = null;
+ this._calculateUV();
+ },
+
+ _refreshTexture: function (texture) {
+ this._texture = texture;
+ this._rect = cc.rect(0, 0, texture.width, texture.height);
+ this._calculateUV();
+ },
+
+ _calculateUV() {
+ let rect = this._rect,
+ texture = this._texture,
+ uv = this.uv,
+ texw = texture.width,
+ texh = texture.height;
+
+ let l = texw === 0 ? 0 : rect.x / texw;
+ let r = texw === 0 ? 0 : (rect.x + rect.width) / texw;
+ let b = texh === 0 ? 0 : (rect.y + rect.height) / texh;
+ let t = texh === 0 ? 0 : rect.y / texh;
+
+ uv[0] = l;
+ uv[1] = b;
+ uv[2] = r;
+ uv[3] = b;
+ uv[4] = l;
+ uv[5] = t;
+ uv[6] = r;
+ uv[7] = t;
+ }
+}
+
+module.exports = LabelFrame;
diff --git a/cocos2d/core/renderer/utils/label/letter-font.js b/cocos2d/core/renderer/utils/label/letter-font.js
new file mode 100644
index 00000000000..5e46af03649
--- /dev/null
+++ b/cocos2d/core/renderer/utils/label/letter-font.js
@@ -0,0 +1,313 @@
+/****************************************************************************
+ Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import WebglBmfontAssembler from '../../webgl/assemblers/label/2d/bmfont';
+
+const Label = require('../../../components/CCLabel');
+const LabelOutline = require('../../../components/CCLabelOutline');
+const textUtils = require('../../../utils/text-utils');
+const Component = require('../../../components/CCComponent');
+const RenderTexture = require('../../../assets/CCRenderTexture');
+const OUTLINE_SUPPORTED = cc.js.isChildClassOf(LabelOutline, Component);
+const getFontFamily = require('../utils').getFontFamily;
+const shareLabelInfo = require('../utils').shareLabelInfo;
+
+
+const FontLetterDefinition = cc.BitmapFont.FontLetterDefinition;
+const FontAtlas = cc.BitmapFont.FontAtlas;
+
+const WHITE = cc.Color.WHITE;
+const space = 0;
+const bleed = 2;
+const _invisibleAlpha = (1 / 255).toFixed(3);
+
+function LetterTexture(char, labelInfo) {
+ this._texture = null;
+ this._labelInfo = labelInfo;
+ this._char = char;
+ this._hash = null;
+ this._data = null;
+ this._canvas = null;
+ this._context = null;
+ this._width = 0;
+ this._height = 0;
+ this._offsetY = 0;
+ this._hash = char.charCodeAt(0) + labelInfo.hash;
+}
+
+LetterTexture.prototype = {
+ constructor: LetterTexture,
+
+ updateRenderData () {
+ this._updateProperties();
+ this._updateTexture();
+ },
+ _updateProperties () {
+ this._texture = new cc.Texture2D();
+ this._data = Label._canvasPool.get();
+ this._canvas = this._data.canvas;
+ this._context = this._data.context;
+ this._context.font = this._labelInfo.fontDesc;
+ let width = textUtils.safeMeasureText(this._context, this._char, this._labelInfo.fontDesc);
+ let blank = this._labelInfo.margin * 2 + bleed;
+ this._width = parseFloat(width.toFixed(2)) + blank;
+ this._height = (1 + textUtils.BASELINE_RATIO) * this._labelInfo.fontSize + blank;
+ this._offsetY = - (this._labelInfo.fontSize * textUtils.BASELINE_RATIO) / 2;
+
+ if (this._canvas.width !== this._width) {
+ this._canvas.width = this._width;
+ }
+
+ if (this._canvas.height !== this._height) {
+ this._canvas.height = this._height;
+ }
+
+ this._texture.initWithElement(this._canvas);
+ },
+ _updateTexture () {
+ let context = this._context;
+ let labelInfo = this._labelInfo,
+ width = this._canvas.width,
+ height = this._canvas.height;
+
+ const fontSize = this._labelInfo.fontSize;
+ let startX = width / 2;
+ let startY = height / 2 + fontSize * textUtils.MIDDLE_RATIO + fontSize * textUtils.BASELINE_OFFSET;
+ let color = labelInfo.color;
+
+ // use round for line join to avoid sharp intersect point
+ context.lineJoin = 'round';
+ context.textAlign = 'center';
+ context.clearRect(0, 0, width, height);
+ //Add a white background to avoid black edges.
+ context.fillStyle = `rgba(${color.r}, ${color.g}, ${color.b}, ${_invisibleAlpha})`;
+ context.fillRect(0, 0, width, height);
+ context.font = labelInfo.fontDesc;
+
+ context.fillStyle = `rgba(${color.r}, ${color.g}, ${color.b}, 1)`;
+ if (labelInfo.isOutlined && labelInfo.margin > 0) {
+ let strokeColor = labelInfo.out || WHITE;
+ context.strokeStyle = `rgba(${strokeColor.r}, ${strokeColor.g}, ${strokeColor.b}, ${strokeColor.a / 255})`;
+ context.lineWidth = labelInfo.margin * 2;
+ context.strokeText(this._char, startX, startY);
+ }
+ context.fillText(this._char, startX, startY);
+
+ this._texture.handleLoadedTexture();
+ },
+
+ destroy () {
+ this._texture.destroy();
+ this._texture = null;
+ Label._canvasPool.put(this._data);
+ },
+}
+
+function LetterAtlas (width, height) {
+ let texture = new RenderTexture();
+ texture.initWithSize(width, height);
+ texture.update();
+
+ this._fontDefDictionary = new FontAtlas(texture);
+
+ this._x = space;
+ this._y = space;
+ this._nexty = space;
+
+ this._width = width;
+ this._height = height;
+
+ cc.director.on(cc.Director.EVENT_BEFORE_SCENE_LAUNCH, this.beforeSceneLoad, this);
+}
+
+cc.js.mixin(LetterAtlas.prototype, {
+ insertLetterTexture (letterTexture) {
+ let texture = letterTexture._texture;
+ let width = texture.width, height = texture.height;
+
+ if ((this._x + width + space) > this._width) {
+ this._x = space;
+ this._y = this._nexty;
+ }
+
+ if ((this._y + height) > this._nexty) {
+ this._nexty = this._y + height + space;
+ }
+
+ if (this._nexty > this._height) {
+ return null;
+ }
+
+ this._fontDefDictionary._texture.drawTextureAt(texture, this._x, this._y);
+
+ this._dirty = true;
+
+ let letter = new FontLetterDefinition();
+ letter.u = this._x + bleed/2;
+ letter.v = this._y + bleed/2;
+ letter.texture = this._fontDefDictionary._texture;
+ letter.valid = true;
+ letter.w = letterTexture._width - bleed;
+ letter.h = letterTexture._height - bleed;
+ letter.xAdvance = letter.w;
+ letter.offsetY = letterTexture._offsetY;
+
+ this._x += width + space;
+
+ this._fontDefDictionary.addLetterDefinitions(letterTexture._hash, letter);
+
+ return letter
+ },
+
+ update () {
+ if (!this._dirty) return;
+ this._fontDefDictionary._texture.update();
+ this._dirty = false;
+ },
+
+ reset () {
+ this._x = space;
+ this._y = space;
+ this._nexty = space;
+
+ let chars = this._fontDefDictionary._letterDefinitions;
+ for (let i = 0, l = chars.length; i < l; i++) {
+ let char = chars[i];
+ if (!char.isValid) {
+ continue;
+ }
+ char.destroy();
+ }
+
+ this._fontDefDictionary.clear();
+ },
+
+ destroy () {
+ this.reset();
+ this._fontDefDictionary._texture.destroy();
+ this._fontDefDictionary._texture = null;
+ },
+
+ beforeSceneLoad () {
+ this.clearAllCache();
+ },
+
+ clearAllCache () {
+ this.destroy();
+
+ let texture = new RenderTexture();
+ texture.initWithSize(this._width, this._height);
+ texture.update();
+
+ this._fontDefDictionary._texture = texture;
+ },
+
+ getLetter (key) {
+ return this._fontDefDictionary._letterDefinitions[key];
+ },
+
+ getTexture () {
+ return this._fontDefDictionary.getTexture();
+ },
+
+ getLetterDefinitionForChar: function(char, labelInfo) {
+ let hash = char.charCodeAt(0) + labelInfo.hash;
+ let letter = this._fontDefDictionary._letterDefinitions[hash];
+ if (!letter) {
+ let temp = new LetterTexture(char, labelInfo);
+ temp.updateRenderData();
+ letter = this.insertLetterTexture(temp);
+ temp.destroy();
+ }
+
+ return letter;
+ }
+});
+
+function computeHash (labelInfo) {
+ let hashData = '';
+ let color = labelInfo.color.toHEX();
+ let out = '';
+ if (labelInfo.isOutlined && labelInfo.margin > 0) {
+ out = out + labelInfo.margin + labelInfo.out.toHEX();
+ }
+
+ return hashData + labelInfo.fontSize + labelInfo.fontFamily + color + out;
+}
+
+let _shareAtlas = null;
+
+let _atlasWidth = 2048;
+let _atlasHeight = 2048;
+let _isBold = false;
+
+export default class LetterFontAssembler extends WebglBmfontAssembler {
+ _getAssemblerData () {
+ if (!_shareAtlas) {
+ _shareAtlas = new LetterAtlas(_atlasWidth, _atlasHeight);
+ cc.Label._shareAtlas = _shareAtlas;
+ }
+
+ return _shareAtlas.getTexture();
+ }
+
+ _updateFontFamily (comp) {
+ shareLabelInfo.fontAtlas = _shareAtlas;
+ shareLabelInfo.fontFamily = getFontFamily(comp);
+
+ // outline
+ let outline = OUTLINE_SUPPORTED && comp.getComponent(LabelOutline);
+ if (outline && outline.enabled) {
+ shareLabelInfo.isOutlined = true;
+ shareLabelInfo.margin = outline.width;
+ shareLabelInfo.out = outline.color.clone();
+ shareLabelInfo.out.a = outline.color.a * comp.node.color.a / 255.0;
+ }
+ else {
+ shareLabelInfo.isOutlined = false;
+ shareLabelInfo.margin = 0;
+ }
+ }
+
+ _updateLabelInfo (comp) {
+ shareLabelInfo.fontDesc = this._getFontDesc();
+ shareLabelInfo.color = comp.node.color;
+ shareLabelInfo.hash = computeHash(shareLabelInfo);
+ }
+
+ _getFontDesc () {
+ let fontDesc = shareLabelInfo.fontSize.toString() + 'px ';
+ fontDesc = fontDesc + shareLabelInfo.fontFamily;
+ if (_isBold) {
+ fontDesc = "bold " + fontDesc;
+ }
+
+ return fontDesc;
+ }
+ _computeHorizontalKerningForText () {}
+ _determineRect (tempRect) {
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/cocos2d/core/renderer/utils/label/ttf.js b/cocos2d/core/renderer/utils/label/ttf.js
index 1c4e9b56119..56edd9bbebd 100644
--- a/cocos2d/core/renderer/utils/label/ttf.js
+++ b/cocos2d/core/renderer/utils/label/ttf.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -23,16 +23,19 @@
THE SOFTWARE.
****************************************************************************/
-const macro = require('../../../platform/CCMacro');
-const textUtils = require('../../../utils/text-utils');
+import Assembler2D from '../../assembler-2d';
-const Component = require('../../../components/CCComponent');
+let textUtils = require('../../../utils/text-utils');
+const macro = require('../../../platform/CCMacro');
const Label = require('../../../components/CCLabel');
const LabelOutline = require('../../../components/CCLabelOutline');
+const LabelShadow = require('../../../components/CCLabelShadow');
const Overflow = Label.Overflow;
+const deleteFromDynamicAtlas = require('../utils').deleteFromDynamicAtlas;
+const getFontFamily = require('../utils').getFontFamily;
-const WHITE = cc.Color.WHITE;
-const OUTLINE_SUPPORTED = cc.js.isChildClassOf(LabelOutline, Component);
+const MAX_SIZE = 2048;
+const _invisibleAlpha = (1 / 255).toFixed(3);
let _context = null;
let _canvas = null;
@@ -41,9 +44,9 @@ let _texture = null;
let _fontDesc = '';
let _string = '';
let _fontSize = 0;
-let _drawFontsize = 0;
+let _drawFontSize = 0;
let _splitedStrings = [];
-let _canvasSize = cc.size();
+let _canvasSize = cc.Size.ZERO;
let _lineHeight = 0;
let _hAlign = 0;
let _vAlign = 0;
@@ -51,137 +54,130 @@ let _color = null;
let _fontFamily = '';
let _overflow = Overflow.NONE;
let _isWrapText = false;
+let _premultiply = false;
// outline
-let _isOutlined = false;
-let _outlineColor = null;
-let _outlineWidth = 0;
-let _margin = 0;
+let _outlineComp = null;
+let _outlineColor = cc.Color.WHITE;
-let _isBold = false;
-let _isItalic = false;
-let _isUnderline = false;
+// shadow
+let _shadowComp = null;
+let _shadowColor = cc.Color.BLACK;
-let _sharedLabelData;
+let _canvasPadding = cc.rect();
+let _contentSizeExtend = cc.Size.ZERO;
+let _nodeContentSize = cc.Size.ZERO;
-//
-let _canvasPool = {
- pool: [],
- get () {
- let data = this.pool.pop();
-
- if (!data) {
- let canvas = document.createElement("canvas");
- let context = canvas.getContext("2d");
- data = {
- canvas: canvas,
- context: context
- }
- }
+let _enableBold = false;
+let _enableItalic = false;
+let _enableUnderline = false;
+let _underlineThickness = 0;
- return data;
- },
- put (canvas) {
- if (this.pool.length >= 32) {
- return;
- }
- this.pool.push(canvas);
- }
-};
+let _drawUnderlinePos = cc.Vec2.ZERO;
+let _drawUnderlineWidth = 0;
+let _sharedLabelData;
-module.exports = {
+const Alignment = [
+ 'left', // macro.TextAlignment.LEFT
+ 'center', // macro.TextAlignment.CENTER
+ 'right' // macro.TextAlignment.RIGHT
+];
+export default class TTFAssembler extends Assembler2D {
_getAssemblerData () {
- if (cc.game.renderType === cc.game.RENDER_TYPE_CANVAS) {
- _sharedLabelData = _canvasPool.get();
- }
- else {
- if (!_sharedLabelData) {
- let labelCanvas = document.createElement("canvas");
- _sharedLabelData = {
- canvas: labelCanvas,
- context: labelCanvas.getContext("2d")
- };
- }
- }
+ _sharedLabelData = Label._canvasPool.get();
_sharedLabelData.canvas.width = _sharedLabelData.canvas.height = 1;
return _sharedLabelData;
- },
+ }
_resetAssemblerData (assemblerData) {
- if (cc.game.renderType === cc.game.RENDER_TYPE_CANVAS && assemblerData) {
- _canvasPool.put(assemblerData);
+ if (assemblerData) {
+ Label._canvasPool.put(assemblerData);
}
- },
+ }
updateRenderData (comp) {
- if (!comp._renderData.vertDirty) return;
+ super.updateRenderData(comp);
+
+ if (!comp._vertsDirty) return;
- this._updateFontFamly(comp);
this._updateProperties(comp);
this._calculateLabelFont();
- this._calculateSplitedStrings();
this._updateLabelDimensions();
- this._calculateTextBaseline();
this._updateTexture(comp);
+ this._calDynamicAtlas(comp);
comp._actualFontSize = _fontSize;
- comp.node.setContentSize(_canvasSize);
+ comp.node.setContentSize(_nodeContentSize);
- this._updateVerts(comp);
+ this.updateVerts(comp);
- comp._renderData.vertDirty = comp._renderData.uvDirty = false;
+ comp._vertsDirty = false;
_context = null;
_canvas = null;
_texture = null;
- },
+ }
- _updateVerts () {
- },
+ updateVerts () {
+ }
- _updateFontFamly (comp) {
- if (!comp.useSystemFont) {
- if (comp.font) {
- if (comp.font._nativeAsset) {
- _fontFamily = comp.font._nativeAsset;
- }
- else {
- cc.loader.load(comp.font.nativeUrl, function (err, fontFamily) {
- _fontFamily = fontFamily || 'Arial';
- comp._updateRenderData(true);
- });
- }
- }
- else {
- _fontFamily = 'Arial';
- }
- }
- else {
- _fontFamily = comp.fontFamily;
- }
- },
+ _updatePaddingRect () {
+ let top = 0, bottom = 0, left = 0, right = 0;
+ let outlineWidth = 0;
+ _contentSizeExtend.width = _contentSizeExtend.height = 0;
+ if (_outlineComp) {
+ outlineWidth = _outlineComp.width;
+ top = bottom = left = right = outlineWidth;
+ _contentSizeExtend.width = _contentSizeExtend.height = outlineWidth * 2;
+ }
+ if (_shadowComp) {
+ let shadowWidth = _shadowComp.blur + outlineWidth;
+ left = Math.max(left, -_shadowComp._offset.x + shadowWidth);
+ right = Math.max(right, _shadowComp._offset.x + shadowWidth);
+ top = Math.max(top, _shadowComp._offset.y + shadowWidth);
+ bottom = Math.max(bottom, -_shadowComp._offset.y + shadowWidth);
+ }
+ if (_enableItalic) {
+ //0.0174532925 = 3.141592653 / 180
+ let offset = _drawFontSize * Math.tan(12 * 0.0174532925);
+ right += offset;
+ _contentSizeExtend.width += offset;
+ }
+ _canvasPadding.x = left;
+ _canvasPadding.y = top;
+ _canvasPadding.width = left + right;
+ _canvasPadding.height = top + bottom;
+ }
_updateProperties (comp) {
let assemblerData = comp._assemblerData;
_context = assemblerData.context;
_canvas = assemblerData.canvas;
- _texture = comp._texture;
-
+ _texture = comp._frame._original ? comp._frame._original._texture : comp._frame._texture;
+
_string = comp.string.toString();
_fontSize = comp._fontSize;
- _drawFontsize = _fontSize;
+ _drawFontSize = _fontSize;
+ _underlineThickness = comp.underlineHeight || _drawFontSize / 8;
_overflow = comp.overflow;
_canvasSize.width = comp.node.width;
_canvasSize.height = comp.node.height;
+ _nodeContentSize = comp.node.getContentSize();
_lineHeight = comp._lineHeight;
_hAlign = comp.horizontalAlign;
_vAlign = comp.verticalAlign;
_color = comp.node.color;
- _isBold = comp._isBold;
- _isItalic = comp._isItalic;
- _isUnderline = comp._isUnderline;
+ _enableBold = comp.enableBold;
+ _enableItalic = comp.enableItalic;
+ _enableUnderline = comp.enableUnderline;
+ _fontFamily = getFontFamily(comp);
+ _premultiply = comp.srcBlendFactor === cc.macro.BlendFactor.ONE;
+
+ if (CC_NATIVERENDERER) {
+ _context._setPremultiply(_premultiply);
+ }
if (_overflow === Overflow.NONE) {
_isWrapText = false;
@@ -194,308 +190,352 @@ module.exports = {
}
// outline
- let outline = OUTLINE_SUPPORTED && comp.getComponent(LabelOutline);
- if (outline && outline.enabled) {
- _isOutlined = true;
- _margin = _outlineWidth = outline.width;
- _outlineColor = cc.color(outline.color);
- // TODO: temporary solution, cascade opacity for outline color
- _outlineColor.a = _outlineColor.a * comp.node.color.a / 255.0;
+ _outlineComp = LabelOutline && comp.getComponent(LabelOutline);
+ _outlineComp = (_outlineComp && _outlineComp.enabled && _outlineComp.width > 0) ? _outlineComp : null;
+ if (_outlineComp) {
+ _outlineColor.set(_outlineComp.color);
}
- else {
- _isOutlined = false;
- _margin = 0;
+
+ // shadow
+ _shadowComp = LabelShadow && comp.getComponent(LabelShadow);
+ _shadowComp = (_shadowComp && _shadowComp.enabled) ? _shadowComp : null;
+ if (_shadowComp) {
+ _shadowColor.set(_shadowComp.color);
+ // TODO: temporary solution, cascade opacity for outline color
+ _shadowColor.a = _shadowColor.a * comp.node.color.a / 255.0;
}
- },
- _calculateFillTextStartPosition () {
- let lineHeight = this._getLineHeight();
- let lineCount = _splitedStrings.length;
- let labelX;
- let firstLinelabelY;
+ this._updatePaddingRect();
+ }
+ _calculateFillTextStartPosition () {
+ let labelX = 0;
if (_hAlign === macro.TextAlignment.RIGHT) {
- labelX = _canvasSize.width - _margin;
- }
- else if (_hAlign === macro.TextAlignment.CENTER) {
- labelX = _canvasSize.width / 2;
+ labelX = _canvasSize.width - _canvasPadding.width;
+ } else if (_hAlign === macro.TextAlignment.CENTER) {
+ labelX = (_canvasSize.width - _canvasPadding.width) / 2;
}
- else {
- labelX = 0 + _margin;
- }
-
- if (_vAlign === macro.VerticalTextAlignment.TOP) {
- firstLinelabelY = 0;
- }
- else if (_vAlign === macro.VerticalTextAlignment.CENTER) {
- firstLinelabelY = _canvasSize.height / 2 - lineHeight * (lineCount - 1) / 2;
- }
- else {
- firstLinelabelY = _canvasSize.height - lineHeight * (lineCount - 1);
- }
-
- return cc.v2(labelX, firstLinelabelY);
- },
- _updateTexture () {
- _context.clearRect(0, 0, _canvas.width, _canvas.height);
- _context.font = _fontDesc;
-
- let startPosition = this._calculateFillTextStartPosition();
let lineHeight = this._getLineHeight();
- //use round for line join to avoid sharp intersect point
- _context.lineJoin = 'round';
- _context.fillStyle = `rgba(${_color.r}, ${_color.g}, ${_color.b}, ${_color.a / 255})`;
- let underlineStartPosition;
-
- //do real rendering
- for (let i = 0; i < _splitedStrings.length; ++i) {
- if (_isOutlined) {
- let strokeColor = _outlineColor || WHITE;
- _context.strokeStyle = `rgba(${strokeColor.r}, ${strokeColor.g}, ${strokeColor.b}, ${strokeColor.a / 255})`;
- _context.lineWidth = _outlineWidth * 2;
- _context.strokeText(_splitedStrings[i], startPosition.x, startPosition.y + i * lineHeight);
- }
- _context.fillText(_splitedStrings[i], startPosition.x, startPosition.y + i * lineHeight);
-
- if (_isUnderline) {
- underlineStartPosition = this._calculateUnderlineStartPosition();
- _context.save();
- _context.beginPath();
- _context.lineWidth = _fontSize / 8;
- _context.strokeStyle = `rgba(${_color.r}, ${_color.g}, ${_color.b}, ${_color.a / 255})`;
- _context.moveTo(underlineStartPosition.x, underlineStartPosition.y + i * lineHeight - 1);
- _context.lineTo(underlineStartPosition.x + _canvas.width, underlineStartPosition.y + i * lineHeight - 1);
- _context.stroke();
- _context.restore();
+ let drawStartY = lineHeight * (_splitedStrings.length - 1);
+ // TOP
+ let firstLinelabelY = _fontSize * (1 - textUtils.BASELINE_RATIO / 2);
+ if (_vAlign !== macro.VerticalTextAlignment.TOP) {
+ // free space in vertical direction
+ let blank = drawStartY + _canvasPadding.height + _fontSize - _canvasSize.height;
+ if (_vAlign === macro.VerticalTextAlignment.BOTTOM) {
+ // Unlike BMFont, needs to reserve space below.
+ blank += textUtils.BASELINE_RATIO / 2 * _fontSize;
+ // BOTTOM
+ firstLinelabelY -= blank;
+ } else {
+ // CENTER
+ firstLinelabelY -= blank / 2;
}
}
- _texture.handleLoadedTexture();
- },
+ firstLinelabelY += textUtils.BASELINE_OFFSET * _fontSize;
- _calculateUnderlineStartPosition () {
- let lineHeight = this._getLineHeight();
- let lineCount = _splitedStrings.length;
- let labelX;
- let firstLinelabelY;
+ return cc.v2(labelX + _canvasPadding.x, firstLinelabelY + _canvasPadding.y);
+ }
- labelX = 0 + _margin;
+ _setupOutline () {
+ _context.strokeStyle = `rgba(${_outlineColor.r}, ${_outlineColor.g}, ${_outlineColor.b}, ${_outlineColor.a / 255})`;
+ _context.lineWidth = _outlineComp.width * 2;
+ }
- if (_vAlign === macro.VerticalTextAlignment.TOP) {
- firstLinelabelY = _fontSize;
- }
- else if (_vAlign === macro.VerticalTextAlignment.CENTER) {
- firstLinelabelY = _canvasSize.height / 2 - lineHeight * (lineCount - 1) / 2 + _fontSize / 2;
- }
- else {
- firstLinelabelY = _canvasSize.height - lineHeight * (lineCount - 1);
- }
+ _setupShadow () {
+ _context.shadowColor = `rgba(${_shadowColor.r}, ${_shadowColor.g}, ${_shadowColor.b}, ${_shadowColor.a / 255})`;
+ _context.shadowBlur = _shadowComp.blur;
+ _context.shadowOffsetX = _shadowComp.offset.x;
+ _context.shadowOffsetY = -_shadowComp.offset.y;
+ }
- return cc.v2(labelX, firstLinelabelY);
- },
+ _drawTextEffect (startPosition, lineHeight) {
+ if (!_shadowComp && !_outlineComp && !_enableUnderline) return;
- _updateLabelDimensions () {
- let paragraphedStrings = _string.split('\n');
+ let isMultiple = _splitedStrings.length > 1 && _shadowComp;
+ let measureText = this._measureText(_context, _fontDesc);
+ let drawTextPosX = 0, drawTextPosY = 0;
- if (_overflow === Overflow.RESIZE_HEIGHT) {
- _canvasSize.height = _splitedStrings.length * this._getLineHeight();
+ // only one set shadow and outline
+ if (_shadowComp) {
+ this._setupShadow();
}
- else if (_overflow === Overflow.NONE) {
- _splitedStrings = paragraphedStrings;
- let canvasSizeX = 0;
- let canvasSizeY = 0;
- for (let i = 0; i < paragraphedStrings.length; ++i) {
- let paraLength = textUtils.safeMeasureText(_context, paragraphedStrings[i]);
- canvasSizeX = canvasSizeX > paraLength ? canvasSizeX : paraLength;
+
+ if (_outlineComp) {
+ this._setupOutline();
+ }
+
+ // draw shadow and (outline or text)
+ for (let i = 0; i < _splitedStrings.length; ++i) {
+ drawTextPosX = startPosition.x;
+ drawTextPosY = startPosition.y + i * lineHeight;
+ // multiple lines need to be drawn outline and fill text
+ if (isMultiple) {
+ if (_outlineComp) {
+ _context.strokeText(_splitedStrings[i], drawTextPosX, drawTextPosY);
+ }
+ _context.fillText(_splitedStrings[i], drawTextPosX, drawTextPosY);
}
- canvasSizeY = _splitedStrings.length * this._getLineHeight();
- _canvasSize.width = parseFloat(canvasSizeX.toFixed(2)) + 2 * _margin;
- _canvasSize.height = parseFloat(canvasSizeY.toFixed(2));
- if (_isItalic) {
- //0.0174532925 = 3.141592653 / 180
- _canvasSize.width += _drawFontsize * Math.tan(12 * 0.0174532925);
+ // draw underline
+ if (_enableUnderline) {
+ _drawUnderlineWidth = measureText(_splitedStrings[i]);
+ if (_hAlign === macro.TextAlignment.RIGHT) {
+ _drawUnderlinePos.x = startPosition.x - _drawUnderlineWidth;
+ } else if (_hAlign === macro.TextAlignment.CENTER) {
+ _drawUnderlinePos.x = startPosition.x - (_drawUnderlineWidth / 2);
+ } else {
+ _drawUnderlinePos.x = startPosition.x;
+ }
+ _drawUnderlinePos.y = drawTextPosY + _drawFontSize / 8;
+ _context.fillRect(_drawUnderlinePos.x, _drawUnderlinePos.y, _drawUnderlineWidth, _underlineThickness);
}
}
- _canvas.width = _canvasSize.width;
- _canvas.height = _canvasSize.height;
- },
-
- _calculateTextBaseline () {
- let node = this._node;
- let hAlign;
- let vAlign;
-
- if (_hAlign === macro.TextAlignment.RIGHT) {
- hAlign = 'right';
- }
- else if (_hAlign === macro.TextAlignment.CENTER) {
- hAlign = 'center';
+ if (isMultiple) {
+ _context.shadowColor = 'transparent';
}
- else {
- hAlign = 'left';
+ }
+
+ _updateTexture () {
+ _context.clearRect(0, 0, _canvas.width, _canvas.height);
+ // use round for line join to avoid sharp intersect point
+ _context.lineJoin = 'round';
+ //Add a white background to avoid black edges.
+ if (!_premultiply) {
+ //TODO: it is best to add alphaTest to filter out the background color.
+ let _fillColor = _outlineComp ? _outlineColor : _color;
+ _context.fillStyle = `rgba(${_fillColor.r}, ${_fillColor.g}, ${_fillColor.b}, ${_invisibleAlpha})`;
+ _context.fillRect(0, 0, _canvas.width, _canvas.height);
+ _context.fillStyle = `rgba(${_color.r}, ${_color.g}, ${_color.b}, 1)`;
+ } else {
+ _context.fillStyle = `rgba(${_color.r}, ${_color.g}, ${_color.b}, ${_color.a / 255.0})`;
}
- _context.textAlign = hAlign;
- if (_vAlign === macro.VerticalTextAlignment.TOP) {
- vAlign = 'top';
+ let startPosition = this._calculateFillTextStartPosition();
+ let lineHeight = this._getLineHeight();
+ let drawTextPosX = startPosition.x, drawTextPosY = 0;
+ // draw shadow and underline
+ this._drawTextEffect(startPosition, lineHeight);
+ // draw text and outline
+ for (let i = 0; i < _splitedStrings.length; ++i) {
+ drawTextPosY = startPosition.y + i * lineHeight;
+ if (_outlineComp) {
+ _context.strokeText(_splitedStrings[i], drawTextPosX, drawTextPosY);
+ }
+ _context.fillText(_splitedStrings[i], drawTextPosX, drawTextPosY);
}
- else if (_vAlign === macro.VerticalTextAlignment.CENTER) {
- vAlign = 'middle';
+
+ if (_shadowComp) {
+ _context.shadowColor = 'transparent';
}
- else {
- vAlign = 'bottom';
+
+ _texture.handleLoadedTexture();
+ }
+
+ _calDynamicAtlas (comp) {
+ if(comp.cacheMode !== Label.CacheMode.BITMAP) return;
+ let frame = comp._frame;
+ // Delete cache in atlas.
+ deleteFromDynamicAtlas(comp, frame);
+ if (!frame._original) {
+ frame.setRect(cc.rect(0, 0, _canvas.width, _canvas.height));
}
- _context.textBaseline = vAlign;
- },
+ this.packToDynamicAtlas(comp, frame);
+ }
- _calculateSplitedStrings () {
- let paragraphedStrings = _string.split('\n');
+ _updateLabelDimensions () {
+ _canvasSize.width = Math.min(_canvasSize.width, MAX_SIZE);
+ _canvasSize.height = Math.min(_canvasSize.height, MAX_SIZE);
- if (_isWrapText) {
- _splitedStrings = [];
- let canvasWidthNoMargin = _canvasSize.width - 2 * _margin;
- for (let i = 0; i < paragraphedStrings.length; ++i) {
- let allWidth = textUtils.safeMeasureText(_context, paragraphedStrings[i]);
- let textFragment = textUtils.fragmentText(paragraphedStrings[i],
- allWidth,
- canvasWidthNoMargin,
- this._measureText(_context));
- _splitedStrings = _splitedStrings.concat(textFragment);
- }
+ let recreate = false;
+ if (_canvas.width !== _canvasSize.width) {
+ _canvas.width = _canvasSize.width;
+ recreate = true
}
- else {
- _splitedStrings = paragraphedStrings;
+
+ if (_canvas.height !== _canvasSize.height) {
+ _canvas.height = _canvasSize.height;
+ recreate = true
}
- },
+ recreate && (_context.font = _fontDesc);
+ // align
+ _context.textAlign = Alignment[_hAlign];
+ }
_getFontDesc () {
let fontDesc = _fontSize.toString() + 'px ';
fontDesc = fontDesc + _fontFamily;
- if (_isBold) {
+ if (_enableBold) {
fontDesc = "bold " + fontDesc;
}
-
+ if (_enableItalic) {
+ fontDesc = "italic " + fontDesc;
+ }
return fontDesc;
- },
+ }
_getLineHeight () {
let nodeSpacingY = _lineHeight;
if (nodeSpacingY === 0) {
nodeSpacingY = _fontSize;
} else {
- nodeSpacingY = nodeSpacingY * _fontSize / _drawFontsize;
+ nodeSpacingY = nodeSpacingY * _fontSize / _drawFontSize;
}
return nodeSpacingY | 0;
- },
+ }
_calculateParagraphLength (paragraphedStrings, ctx) {
let paragraphLength = [];
for (let i = 0; i < paragraphedStrings.length; ++i) {
- let width = textUtils.safeMeasureText(ctx, paragraphedStrings[i]);
+ let width = textUtils.safeMeasureText(ctx, paragraphedStrings[i], _fontDesc);
paragraphLength.push(width);
}
return paragraphLength;
- },
+ }
- _measureText (ctx) {
+ _measureText (ctx, fontDesc) {
return function (string) {
- return textUtils.safeMeasureText(ctx, string);
+ return textUtils.safeMeasureText(ctx, string, fontDesc);
};
- },
-
- _calculateLabelFont () {
- _fontDesc = this._getFontDesc();
- _context.font = _fontDesc;
+ }
- if (_overflow === Overflow.SHRINK) {
- let paragraphedStrings = _string.split('\n');
- let paragraphLength = this._calculateParagraphLength(paragraphedStrings, _context);
+ _calculateShrinkFont (paragraphedStrings) {
+ let paragraphLength = this._calculateParagraphLength(paragraphedStrings, _context);
- _splitedStrings = paragraphedStrings;
- let i = 0;
- let totalHeight = 0;
- let maxLength = 0;
-
- if (_isWrapText) {
- let canvasWidthNoMargin = _canvasSize.width - 2 * _margin;
- let canvasHeightNoMargin = _canvasSize.height - 2 * _margin;
- if (canvasWidthNoMargin < 0 || canvasHeightNoMargin < 0) {
- _fontDesc = this._getFontDesc();
- _context.font = _fontDesc;
- return;
- }
- totalHeight = canvasHeightNoMargin + 1;
- maxLength = canvasWidthNoMargin + 1;
- let actualFontSize = _fontSize + 1;
- let textFragment = "";
- let tryDivideByTwo = true;
- let startShrinkFontSize = actualFontSize | 0;
-
- while (totalHeight > canvasHeightNoMargin || maxLength > canvasWidthNoMargin) {
- if (tryDivideByTwo) {
- actualFontSize = (startShrinkFontSize / 2) | 0;
- } else {
- actualFontSize = startShrinkFontSize - 1;
- startShrinkFontSize = actualFontSize;
- }
- if (actualFontSize <= 0) {
- cc.logID(4003);
- break;
- }
- _fontSize = actualFontSize;
- _fontDesc = this._getFontDesc();
- _context.font = _fontDesc;
-
- _splitedStrings = [];
- totalHeight = 0;
- for (i = 0; i < paragraphedStrings.length; ++i) {
- let j = 0;
- let allWidth = textUtils.safeMeasureText(_context, paragraphedStrings[i]);
- textFragment = textUtils.fragmentText(paragraphedStrings[i],
- allWidth,
- canvasWidthNoMargin,
- this._measureText(_context));
- while (j < textFragment.length) {
- let measureWidth = textUtils.safeMeasureText(_context, textFragment[j]);
- maxLength = measureWidth;
- totalHeight += this._getLineHeight();
- ++j;
- }
- _splitedStrings = _splitedStrings.concat(textFragment);
- }
-
- if (tryDivideByTwo) {
- if (totalHeight > canvasHeightNoMargin) {
- startShrinkFontSize = actualFontSize | 0;
- } else {
- tryDivideByTwo = false;
- totalHeight = canvasHeightNoMargin + 1;
- }
- }
- }
+ let i = 0;
+ let totalHeight = 0;
+ let maxLength = 0;
+
+ if (_isWrapText) {
+ let canvasWidthNoMargin = _nodeContentSize.width;
+ let canvasHeightNoMargin = _nodeContentSize.height;
+ if (canvasWidthNoMargin < 0 || canvasHeightNoMargin < 0) {
+ return;
}
- else {
- totalHeight = paragraphedStrings.length * this._getLineHeight();
+ totalHeight = canvasHeightNoMargin + 1;
+ let actualFontSize = _fontSize + 1;
+ let textFragment = "";
+ //let startShrinkFontSize = actualFontSize | 0;
+ let left = 0, right = actualFontSize | 0, mid = 0;
+
+ while (left < right) {
+ mid = (left + right + 1) >> 1;
+
+ if (mid <= 0) {
+ cc.logID(4003);
+ break;
+ }
+
+ _fontSize = mid;
+ _fontDesc = this._getFontDesc();
+ _context.font = _fontDesc;
+ let lineHeight = this._getLineHeight();
+ totalHeight = 0;
for (i = 0; i < paragraphedStrings.length; ++i) {
- if (maxLength < paragraphLength[i]) {
- maxLength = paragraphLength[i];
- }
+ let allWidth = textUtils.safeMeasureText(_context, paragraphedStrings[i], _fontDesc);
+ textFragment = textUtils.fragmentText(paragraphedStrings[i],
+ allWidth,
+ canvasWidthNoMargin,
+ this._measureText(_context, _fontDesc));
+ totalHeight += textFragment.length * lineHeight;
}
- let scaleX = (_canvasSize.width - 2 * _margin) / maxLength;
- let scaleY = _canvasSize.height / totalHeight;
- _fontSize = (_drawFontsize * Math.min(1, scaleX, scaleY)) | 0;
+ if (totalHeight > canvasHeightNoMargin) {
+ right = mid - 1;
+ } else {
+ left = mid;
+ }
+ }
+
+ if (left === 0) {
+ cc.logID(4003);
+ } else {
+ _fontSize = left;
_fontDesc = this._getFontDesc();
_context.font = _fontDesc;
}
+ } else {
+ totalHeight = paragraphedStrings.length * this._getLineHeight();
+
+ for (i = 0; i < paragraphedStrings.length; ++i) {
+ if (maxLength < paragraphLength[i]) {
+ maxLength = paragraphLength[i];
+ }
+ }
+ let scaleX = (_canvasSize.width - _canvasPadding.width) / maxLength;
+ let scaleY = _canvasSize.height / totalHeight;
+
+ _fontSize = (_drawFontSize * Math.min(1, scaleX, scaleY)) | 0;
+ _fontDesc = this._getFontDesc();
+ _context.font = _fontDesc;
}
}
-};
+
+ _calculateWrapText (paragraphedStrings) {
+ if (!_isWrapText) return;
+
+ _splitedStrings = [];
+ let canvasWidthNoMargin = _nodeContentSize.width;
+ for (let i = 0; i < paragraphedStrings.length; ++i) {
+ let allWidth = textUtils.safeMeasureText(_context, paragraphedStrings[i], _fontDesc);
+ let textFragment = textUtils.fragmentText(paragraphedStrings[i],
+ allWidth,
+ canvasWidthNoMargin,
+ this._measureText(_context, _fontDesc));
+ _splitedStrings = _splitedStrings.concat(textFragment);
+ }
+ }
+
+ _calculateLabelFont () {
+ let paragraphedStrings = _string.split('\n');
+
+ _splitedStrings = paragraphedStrings;
+ _fontDesc = this._getFontDesc();
+ _context.font = _fontDesc;
+
+ switch (_overflow) {
+ case Overflow.NONE: {
+ let canvasSizeX = 0;
+ let canvasSizeY = 0;
+ for (let i = 0; i < paragraphedStrings.length; ++i) {
+ let paraLength = textUtils.safeMeasureText(_context, paragraphedStrings[i], _fontDesc);
+ canvasSizeX = canvasSizeX > paraLength ? canvasSizeX : paraLength;
+ }
+ canvasSizeY = (_splitedStrings.length + textUtils.BASELINE_RATIO) * this._getLineHeight();
+ let rawWidth = parseFloat(canvasSizeX.toFixed(2));
+ let rawHeight = parseFloat(canvasSizeY.toFixed(2));
+ _canvasSize.width = rawWidth + _canvasPadding.width;
+ _canvasSize.height = rawHeight + _canvasPadding.height;
+ _nodeContentSize.width = rawWidth + _contentSizeExtend.width;
+ _nodeContentSize.height = rawHeight + _contentSizeExtend.height;
+ break;
+ }
+ case Overflow.SHRINK: {
+ this._calculateShrinkFont(paragraphedStrings);
+ this._calculateWrapText(paragraphedStrings);
+ break;
+ }
+ case Overflow.CLAMP: {
+ this._calculateWrapText(paragraphedStrings);
+ break;
+ }
+ case Overflow.RESIZE_HEIGHT: {
+ this._calculateWrapText(paragraphedStrings);
+ let rawHeight = (_splitedStrings.length + textUtils.BASELINE_RATIO) * this._getLineHeight();
+ _canvasSize.height = rawHeight + _canvasPadding.height;
+ // set node height
+ _nodeContentSize.height = rawHeight + _contentSizeExtend.height;
+ break;
+ }
+ }
+ }
+}
+
diff --git a/cocos2d/core/renderer/utils/utils.js b/cocos2d/core/renderer/utils/utils.js
new file mode 100644
index 00000000000..350deaa23cb
--- /dev/null
+++ b/cocos2d/core/renderer/utils/utils.js
@@ -0,0 +1,53 @@
+const dynamicAtlasManager = require('./dynamic-atlas/manager');
+const WHITE = cc.Color.WHITE;
+
+// share data of bmfont
+let shareLabelInfo = {
+ fontAtlas: null,
+
+ fontSize:0,
+ lineHeight:0,
+ hAlign:0,
+ vAlign:0,
+
+ hash:"",
+ fontFamily:"",
+ fontDesc:"Arial",
+ color:WHITE,
+ isOutlined:false,
+ out:WHITE,
+ margin:0,
+}
+
+module.exports = {
+
+ deleteFromDynamicAtlas (comp, frame) {
+ if (frame && !CC_TEST) {
+ if (frame._original && dynamicAtlasManager) {
+ dynamicAtlasManager.deleteAtlasSpriteFrame(frame);
+ frame._resetDynamicAtlasFrame();
+ }
+ }
+ },
+
+ getFontFamily (comp) {
+ if (!comp.useSystemFont) {
+ if (comp.font) {
+ if (comp.font._nativeAsset) {
+ return comp.font._nativeAsset;
+ }
+ cc.assetManager.postLoadNative(comp.font, function (err) {
+ comp.setVertsDirty();
+ });
+ return 'Arial';
+ }
+
+ return 'Arial';
+ }
+ else {
+ return comp.fontFamily || 'Arial';
+ }
+ },
+
+ shareLabelInfo: shareLabelInfo
+}
diff --git a/cocos2d/core/renderer/webgl/assemblers/graphics/earcut.js b/cocos2d/core/renderer/webgl/assemblers/graphics/earcut.js
index 0d445172ada..46fae36fda1 100644
--- a/cocos2d/core/renderer/webgl/assemblers/graphics/earcut.js
+++ b/cocos2d/core/renderer/webgl/assemblers/graphics/earcut.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -25,7 +25,7 @@
'use strict';
-module.exports = earcut;
+cc.Graphics.earcut = module.exports = earcut;
function earcut(data, holeIndices, dim) {
diff --git a/cocos2d/core/renderer/webgl/assemblers/graphics/impl.js b/cocos2d/core/renderer/webgl/assemblers/graphics/impl.js
index f66d48931bb..825e397d9e2 100644
--- a/cocos2d/core/renderer/webgl/assemblers/graphics/impl.js
+++ b/cocos2d/core/renderer/webgl/assemblers/graphics/impl.js
@@ -1,14 +1,32 @@
+/****************************************************************************
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
const Helper = require('../../../../graphics/helper');
const PointFlags = require('../../../../graphics/types').PointFlags;
-const MeshBuffer = require('../../mesh-buffer');
-const vfmtPosColor = require('../../vertex-format').vfmtPosColor;
-const renderer = require('../../../index');
-const renderEngine = renderer.renderEngine;
-const IARenderData = renderEngine.IARenderData;
-const InputAssembler = renderEngine.InputAssembler;
-
-let Point = cc.Class({
+
+let Point = cc.Graphics.Point = cc.Class({
name: 'cc.GraphicsPoint',
extends: cc.Vec2,
@@ -63,10 +81,6 @@ function Impl (graphics) {
this._paths = [];
this._points = [];
-
- this._renderDatas = [];
-
- this._dataOffset = 0;
}
cc.js.mixin(Impl.prototype, {
@@ -139,34 +153,16 @@ cc.js.mixin(Impl.prototype, {
this._curPath.complex = false;
},
- clear (comp, clean) {
+ clear (clean) {
this._pathLength = 0;
this._pathOffset = 0;
this._pointsOffset = 0;
-
- this._dataOffset = 0;
-
+
this._curPath = null;
-
- let datas = this._renderDatas;
+
if (clean) {
this._paths.length = 0;
this._points.length = 0;
- // manually destroy render datas
- for (let i = 0, l = datas.length; i < l; i++) {
- let data = datas[i];
- data.meshbuffer.destroy();
- data.meshbuffer = null;
- }
- datas.length = 0;
- }
- else {
- for (let i = 0, l = datas.length; i < l; i++) {
- let data = datas[i];
-
- let meshbuffer = data.meshbuffer;
- meshbuffer.reset();
- }
}
},
@@ -215,28 +211,7 @@ cc.js.mixin(Impl.prototype, {
pathPoints.push(pt);
},
- requestRenderData () {
- let renderData = new IARenderData();
- let meshbuffer = new MeshBuffer(renderer._walker, vfmtPosColor);
- renderData.meshbuffer = meshbuffer;
- this._renderDatas.push(renderData);
-
- let ia = new InputAssembler();
- ia._vertexBuffer = meshbuffer._vb;
- ia._indexBuffer = meshbuffer._ib;
- ia._start = 0;
- renderData.ia = ia;
-
- return renderData;
- },
-
- getRenderDatas () {
- if (this._renderDatas.length === 0) {
- this.requestRenderData();
- }
-
- return this._renderDatas;
- }
});
+cc.Graphics._Impl = Impl;
module.exports = Impl;
diff --git a/cocos2d/core/renderer/webgl/assemblers/graphics/index.js b/cocos2d/core/renderer/webgl/assemblers/graphics/index.js
index 2d38456598b..10b2e78c653 100644
--- a/cocos2d/core/renderer/webgl/assemblers/graphics/index.js
+++ b/cocos2d/core/renderer/webgl/assemblers/graphics/index.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -23,12 +23,19 @@
THE SOFTWARE.
****************************************************************************/
+import Assembler from '../../../assembler';
+
+import InputAssembler from '../../../../../renderer/core/input-assembler';
+
+const MeshBuffer = require('../../mesh-buffer');
+const renderer = require('../../../index');
+
const Graphics = require('../../../../graphics/graphics');
const PointFlags = require('../../../../graphics/types').PointFlags;
const LineJoin = Graphics.LineJoin;
const LineCap = Graphics.LineCap;
const Earcut = require('./earcut');
-const Impl = require('./impl');
+require('./impl');
const MAX_VERTEX = 65535;
const MAX_INDICE = MAX_VERTEX * 2;
@@ -41,11 +48,6 @@ const acos = Math.acos;
const cos = Math.cos;
const sin = Math.sin;
const atan2 = Math.atan2;
-const abs = Math.abs;
-
-let _renderData = null;
-let _impl = null;
-let _curColor = 0;
function curveDivs (r, arc, tol) {
let da = acos(r / (r + tol)) * 2.0;
@@ -62,93 +64,143 @@ function clamp (v, min, max) {
return v;
}
-let graphicsAssembler = {
- useModel: true,
- createImpl (graphics) {
- return new Impl(graphics);
- },
- updateRenderData (graphics) {
- let datas = graphics._impl.getRenderDatas();
- for (let i = 0, l = datas.length; i < l; i++) {
- datas[i].material = graphics.getMaterial();
+let gfx = cc.gfx;
+let vfmtPosColorSdf = new gfx.VertexFormat([
+ { name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
+ { name: gfx.ATTR_COLOR, type: gfx.ATTR_TYPE_UINT8, num: 4, normalize: true },
+ { name: 'a_dist', type: gfx.ATTR_TYPE_FLOAT32, num: 1 },
+]);
+vfmtPosColorSdf.name = 'vfmtPosColorSdf';
+
+export default class GraphicsAssembler extends Assembler {
+ constructor (graphics) {
+ super(graphics);
+
+ this._buffer = null;
+ this._buffers = [];
+ this._bufferOffset = 0;
+ }
+
+ getVfmt () {
+ return vfmtPosColorSdf;
+ }
+
+ getVfmtFloatCount () {
+ return 4;
+ }
+
+ requestBuffer () {
+ let buffer = {
+ indiceStart: 0,
+ vertexStart: 0
+ };
+
+ let meshbuffer = new MeshBuffer(renderer._handle, this.getVfmt());
+ buffer.meshbuffer = meshbuffer;
+
+ let ia = new InputAssembler(meshbuffer._vb, meshbuffer._ib);
+ buffer.ia = ia;
+
+ this._buffers.push(buffer);
+
+ return buffer;
+ }
+
+ getBuffers () {
+ if (this._buffers.length === 0) {
+ this.requestBuffer();
+ }
+
+ return this._buffers;
+ }
+
+ clear (clean) {
+ this._bufferOffset = 0;
+
+ let datas = this._buffers;
+ if (clean) {
+ for (let i = 0, l = datas.length; i < l; i++) {
+ let data = datas[i];
+ data.meshbuffer.destroy();
+ data.meshbuffer = null;
+ }
+ datas.length = 0;
+ }
+ else {
+ for (let i = 0, l = datas.length; i < l; i++) {
+ let data = datas[i];
+
+ data.indiceStart = 0;
+ data.vertexStart = 0;
+
+ let meshbuffer = data.meshbuffer;
+ meshbuffer.reset();
+ }
}
- },
+ }
fillBuffers (graphics, renderer) {
renderer._flush();
- let tempNode = renderer.node;
renderer.node = graphics.node;
- this.renderIA(graphics, renderer);
- renderer.node = tempNode;
- },
-
- renderIA (graphics, renderer) {
- let node = graphics.node;
-
- let nodeColor = node.color,
- nodeR = nodeColor.r / 255,
- nodeG = nodeColor.g / 255,
- nodeB = nodeColor.b / 255,
- nodeA = nodeColor.a / 255;
-
- let impl = graphics._impl;
- let renderDatas = impl.getRenderDatas();
- for (let index = 0, length = renderDatas.length; index < length; index++) {
- let renderData = renderDatas[index];
- let meshbuffer = renderData.meshbuffer;
- renderData.ia._count = meshbuffer.indiceStart;
- renderer._flushIA(renderData);
+ renderer.material = graphics._materials[0];
+
+ let buffers = this.getBuffers();
+ for (let index = 0, length = buffers.length; index < length; index++) {
+ let buffer = buffers[index];
+ let meshbuffer = buffer.meshbuffer;
+ buffer.ia._count = buffer.indiceStart;
+ renderer._flushIA(buffer.ia);
meshbuffer.uploadData();
}
- },
+ }
- genRenderData (graphics, cverts) {
- let renderDatas = _impl.getRenderDatas();
- let renderData = renderDatas[_impl._dataOffset];
- let meshbuffer = renderData.meshbuffer;
+ genBuffer (graphics, cverts) {
+ let buffers = this.getBuffers();
+ let buffer = buffers[this._bufferOffset];
+ let meshbuffer = buffer.meshbuffer;
- let maxVertsCount = meshbuffer.vertexStart + cverts;
+ let maxVertsCount = buffer.vertexStart + cverts;
if (maxVertsCount > MAX_VERTEX ||
maxVertsCount * 3 > MAX_INDICE) {
- ++_impl._dataOffset;
+ ++this._bufferOffset;
maxVertsCount = cverts;
- if (_impl._dataOffset < renderDatas.length) {
- renderData = renderDatas[_impl._dataOffset];
+ if (this._bufferOffset < buffers.length) {
+ buffer = buffers[this._bufferOffset];
}
else {
- renderData = _impl.requestRenderData(graphics);
- renderDatas[_impl._dataOffset] = renderData;
+ buffer = this.requestBuffer(graphics);
+ buffers[this._bufferOffset] = buffer;
}
- renderData.material = graphics.getMaterial();
- meshbuffer = renderData.meshbuffer;
+ meshbuffer = buffer.meshbuffer;
}
if (maxVertsCount > meshbuffer.vertexOffset) {
meshbuffer.requestStatic(cverts, cverts*3);
}
- return renderData;
- },
+ this._buffer = buffer;
+ return buffer;
+ }
stroke (graphics) {
- _curColor = graphics._strokeColor._val;
+ this._curColor = graphics._strokeColor._val;
this._flattenPaths(graphics._impl);
this._expandStroke(graphics);
graphics._impl._updatePathOffset = true;
- },
+ }
fill (graphics) {
- _curColor = graphics._fillColor._val;
+ this._curColor = graphics._fillColor._val;
this._expandFill(graphics);
graphics._impl._updatePathOffset = true;
- },
+ }
_expandStroke (graphics) {
let w = graphics.lineWidth * 0.5,
@@ -156,17 +208,17 @@ let graphicsAssembler = {
lineJoin = graphics.lineJoin,
miterLimit = graphics.miterLimit;
- _impl = graphics._impl;
+ let impl = graphics._impl;
- let ncap = curveDivs(w, PI, _impl._tessTol);
+ let ncap = curveDivs(w, PI, impl._tessTol);
- this._calculateJoins(_impl, w, lineJoin, miterLimit);
+ this._calculateJoins(impl, w, lineJoin, miterLimit);
- let paths = _impl._paths;
+ let paths = impl._paths;
// Calculate max vertex usage.
let cverts = 0;
- for (let i = _impl._pathOffset, l = _impl._pathLength; i < l; i++) {
+ for (let i = impl._pathOffset, l = impl._pathLength; i < l; i++) {
let path = paths[i];
let pointsLength = path.points.length;
@@ -183,16 +235,16 @@ let graphicsAssembler = {
}
}
- let renderData = _renderData = this.genRenderData(graphics, cverts),
- meshbuffer = renderData.meshbuffer,
+ let buffer = this.genBuffer(graphics, cverts),
+ meshbuffer = buffer.meshbuffer,
vData = meshbuffer._vData,
iData = meshbuffer._iData;
- for (let i = _impl._pathOffset, l = _impl._pathLength; i < l; i++) {
+ for (let i = impl._pathOffset, l = impl._pathLength; i < l; i++) {
let path = paths[i];
let pts = path.points;
let pointsLength = pts.length;
- let offset = meshbuffer.vertexStart;
+ let offset = buffer.vertexStart;
let p0, p1;
let start, end, loop;
@@ -210,6 +262,8 @@ let graphicsAssembler = {
start = 1;
end = pointsLength - 1;
}
+
+ p1 = p1 || p0;
if (!loop) {
// Add cap
@@ -220,9 +274,9 @@ let graphicsAssembler = {
let dy = dPos.y;
if (lineCap === LineCap.BUTT)
- this._buttCap(p0, dx, dy, w, 0);
+ this._buttCapStart(p0, dx, dy, w, 0);
else if (lineCap === LineCap.SQUARE)
- this._buttCap(p0, dx, dy, w, w);
+ this._buttCapStart(p0, dx, dy, w, w);
else if (lineCap === LineCap.ROUND)
this._roundCapStart(p0, dx, dy, w, ncap);
}
@@ -235,8 +289,8 @@ let graphicsAssembler = {
this._bevelJoin(p0, p1, w, w);
}
else {
- this._vset(p1.x + p1.dmx * w, p1.y + p1.dmy * w);
- this._vset(p1.x - p1.dmx * w, p1.y - p1.dmy * w);
+ this._vset(p1.x + p1.dmx * w, p1.y + p1.dmy * w, 1);
+ this._vset(p1.x - p1.dmx * w, p1.y - p1.dmy * w, -1);
}
p0 = p1;
@@ -245,9 +299,10 @@ let graphicsAssembler = {
if (loop) {
// Loop it
- let vDataoOfset = offset * 3;
- this._vset(vData[vDataoOfset], vData[vDataoOfset+1]);
- this._vset(vData[vDataoOfset+3], vData[vDataoOfset+4]);
+ let floatCount = this.getVfmtFloatCount();
+ let vDataoOfset = offset * floatCount;
+ this._vset(vData[vDataoOfset], vData[vDataoOfset+1], 1);
+ this._vset(vData[vDataoOfset+floatCount], vData[vDataoOfset+floatCount+1], -1);
} else {
// Add cap
let dPos = p1.sub(p0);
@@ -257,48 +312,45 @@ let graphicsAssembler = {
let dy = dPos.y;
if (lineCap === LineCap.BUTT)
- this._buttCap(p1, dx, dy, w, 0);
- else if (lineCap === LineCap.BUTT || lineCap === LineCap.SQUARE)
- this._buttCap(p1, dx, dy, w, w);
+ this._buttCapEnd(p1, dx, dy, w, 0);
+ else if (lineCap === LineCap.SQUARE)
+ this._buttCapEnd(p1, dx, dy, w, w);
else if (lineCap === LineCap.ROUND)
this._roundCapEnd(p1, dx, dy, w, ncap);
}
// stroke indices
- let indicesOffset = meshbuffer.indiceStart;
- for (let start = offset+2, end = meshbuffer.vertexStart; start < end; start++) {
+ let indicesOffset = buffer.indiceStart;
+ for (let start = offset+2, end = buffer.vertexStart; start < end; start++) {
iData[indicesOffset++] = start - 2;
iData[indicesOffset++] = start - 1;
iData[indicesOffset++] = start;
}
- meshbuffer.indiceStart = indicesOffset;
+ buffer.indiceStart = indicesOffset;
}
-
- _renderData = null;
- _impl = null;
- },
+ }
_expandFill (graphics) {
- _impl = graphics._impl;
+ let impl = graphics._impl;
- let paths = _impl._paths;
+ let paths = impl._paths;
// Calculate max vertex usage.
let cverts = 0;
- for (let i = _impl._pathOffset, l = _impl._pathLength; i < l; i++) {
+ for (let i = impl._pathOffset, l = impl._pathLength; i < l; i++) {
let path = paths[i];
let pointsLength = path.points.length;
cverts += pointsLength;
}
- let renderData = _renderData = this.genRenderData(graphics, cverts),
- meshbuffer = renderData.meshbuffer,
+ let buffer = this.genBuffer(graphics, cverts),
+ meshbuffer = buffer.meshbuffer,
vData = meshbuffer._vData,
iData = meshbuffer._iData;
- for (let i = _impl._pathOffset, l = _impl._pathLength; i < l; i++) {
+ for (let i = impl._pathOffset, l = impl._pathLength; i < l; i++) {
let path = paths[i];
let pts = path.points;
let pointsLength = pts.length;
@@ -308,18 +360,19 @@ let graphicsAssembler = {
}
// Calculate shape vertices.
- let offset = meshbuffer.vertexStart;
+ let offset = buffer.vertexStart;
for (let j = 0; j < pointsLength; ++j) {
this._vset(pts[j].x, pts[j].y);
}
- let indicesOffset = meshbuffer.indiceStart;
+ let indicesOffset = buffer.indiceStart;
if (path.complex) {
let earcutData = [];
- for (let j = offset, end = meshbuffer.vertexStart; j < end; j++) {
- let vDataOffset = j * 3;
+ let floatCount = this.getVfmtFloatCount();
+ for (let j = offset, end = buffer.vertexStart; j < end; j++) {
+ let vDataOffset = j * floatCount;
earcutData.push(vData[vDataOffset]);
earcutData.push(vData[vDataOffset+1]);
}
@@ -336,19 +389,16 @@ let graphicsAssembler = {
}
else {
let first = offset;
- for (let start = offset+2, end = meshbuffer.vertexStart; start < end; start++) {
+ for (let start = offset+2, end = buffer.vertexStart; start < end; start++) {
iData[indicesOffset++] = first;
iData[indicesOffset++] = start - 1;
iData[indicesOffset++] = start;
}
}
- meshbuffer.indiceStart = indicesOffset;
+ buffer.indiceStart = indicesOffset;
}
-
- _renderData = null;
- _impl = null;
- },
+ }
_calculateJoins (impl, w, lineJoin, miterLimit) {
let iw = 0.0;
@@ -420,7 +470,7 @@ let graphicsAssembler = {
p1 = pts[j + 1];
}
}
- },
+ }
_flattenPaths (impl) {
let paths = impl._paths;
@@ -431,7 +481,7 @@ let graphicsAssembler = {
let p0 = pts[pts.length - 1];
let p1 = pts[0];
- if (p0.equals(p1)) {
+ if (pts.length > 2 && p0.equals(p1)) {
path.closed = true;
pts.pop();
p0 = pts[pts.length - 1];
@@ -450,7 +500,7 @@ let graphicsAssembler = {
p1 = pts[j + 1];
}
}
- },
+ }
_chooseBevel (bevel, p0, p1, w) {
let x = p1.x;
@@ -468,17 +518,27 @@ let graphicsAssembler = {
}
return [x0, y0, x1, y1];
- },
+ }
- _buttCap (p, dx, dy, w, d) {
+ _buttCapStart (p, dx, dy, w, d) {
let px = p.x - dx * d;
let py = p.y - dy * d;
let dlx = dy;
let dly = -dx;
- this._vset(px + dlx * w, py + dly * w);
- this._vset(px - dlx * w, py - dly * w);
- },
+ this._vset(px + dlx * w, py + dly * w, 1);
+ this._vset(px - dlx * w, py - dly * w, -1);
+ }
+
+ _buttCapEnd (p, dx, dy, w, d) {
+ let px = p.x + dx * d;
+ let py = p.y + dy * d;
+ let dlx = dy;
+ let dly = -dx;
+
+ this._vset(px + dlx * w, py + dly * w, 1);
+ this._vset(px - dlx * w, py - dly * w, -1);
+ }
_roundCapStart (p, dx, dy, w, ncap) {
let px = p.x;
@@ -490,12 +550,12 @@ let graphicsAssembler = {
let a = i / (ncap - 1) * PI;
let ax = cos(a) * w,
ay = sin(a) * w;
- this._vset(px - dlx * ax - dx * ay, py - dly * ax - dy * ay);
- this._vset(px, py);
+ this._vset(px - dlx * ax - dx * ay, py - dly * ax - dy * ay, 1);
+ this._vset(px, py, 0);
}
- this._vset(px + dlx * w, py + dly * w);
- this._vset(px - dlx * w, py - dly * w);
- },
+ this._vset(px + dlx * w, py + dly * w, 1);
+ this._vset(px - dlx * w, py - dly * w, -1);
+ }
_roundCapEnd (p, dx, dy, w, ncap) {
let px = p.x;
@@ -503,16 +563,16 @@ let graphicsAssembler = {
let dlx = dy;
let dly = -dx;
- this._vset(px + dlx * w, py + dly * w);
- this._vset(px - dlx * w, py - dly * w);
+ this._vset(px + dlx * w, py + dly * w, 1);
+ this._vset(px - dlx * w, py - dly * w, -1);
for (let i = 0; i < ncap; i++) {
let a = i / (ncap - 1) * PI;
let ax = cos(a) * w,
ay = sin(a) * w;
- this._vset(px, py);
- this._vset(px - dlx * ax + dx * ay, py - dly * ax + dy * ay);
+ this._vset(px, py, 0);
+ this._vset(px - dlx * ax + dx * ay, py - dly * ax + dy * ay, 1);
}
- },
+ }
_roundJoin (p0, p1, lw, rw, ncap) {
let dlx0 = p0.dy;
@@ -534,8 +594,8 @@ let graphicsAssembler = {
let a1 = atan2(-dly1, -dlx1);
if (a1 > a0) a1 -= PI * 2;
- this._vset(lx0, ly0);
- this._vset(p1x - dlx0 * rw, p1.y - dly0 * rw);
+ this._vset(lx0, ly0, 1);
+ this._vset(p1x - dlx0 * rw, p1.y - dly0 * rw, -1);
let n = clamp(ceil((a0 - a1) / PI) * ncap, 2, ncap);
for (let i = 0; i < n; i++) {
@@ -543,12 +603,12 @@ let graphicsAssembler = {
let a = a0 + u * (a1 - a0);
let rx = p1x + cos(a) * rw;
let ry = p1y + sin(a) * rw;
- this._vset(p1x, p1y);
- this._vset(rx, ry);
+ this._vset(p1x, p1y, 0);
+ this._vset(rx, ry, -1);
}
- this._vset(lx1, ly1);
- this._vset(p1x - dlx1 * rw, p1y - dly1 * rw);
+ this._vset(lx1, ly1, 1);
+ this._vset(p1x - dlx1 * rw, p1y - dly1 * rw, -1);
} else {
let out = this._chooseBevel(p1.flags & PointFlags.PT_INNERBEVEL, p0, p1, -rw);
let rx0 = out[0];
@@ -560,8 +620,8 @@ let graphicsAssembler = {
let a1 = atan2(dly1, dlx1);
if (a1 < a0) a1 += PI * 2;
- this._vset(p1x + dlx0 * rw, p1y + dly0 * rw);
- this._vset(rx0, ry0);
+ this._vset(p1x + dlx0 * rw, p1y + dly0 * rw, 1);
+ this._vset(rx0, ry0, -1);
let n = clamp(ceil((a1 - a0) / PI) * ncap, 2, ncap);
for (let i = 0; i < n; i++) {
@@ -569,14 +629,14 @@ let graphicsAssembler = {
let a = a0 + u * (a1 - a0);
let lx = p1x + cos(a) * lw;
let ly = p1y + sin(a) * lw;
- this._vset(lx, ly);
- this._vset(p1x, p1y);
+ this._vset(lx, ly, 1);
+ this._vset(p1x, p1y, 0);
}
- this._vset(p1x + dlx1 * rw, p1y + dly1 * rw);
- this._vset(rx1, ry1);
+ this._vset(p1x + dlx1 * rw, p1y + dly1 * rw, 1);
+ this._vset(rx1, ry1, -1);
}
- },
+ }
_bevelJoin (p0, p1, lw, rw) {
let rx0, ry0, rx1, ry1;
@@ -593,11 +653,11 @@ let graphicsAssembler = {
lx1 = out[2];
ly1 = out[3];
- this._vset(lx0, ly0);
- this._vset(p1.x - dlx0 * rw, p1.y - dly0 * rw);
+ this._vset(lx0, ly0, 1);
+ this._vset(p1.x - dlx0 * rw, p1.y - dly0 * rw, -1);
- this._vset(lx1, ly1);
- this._vset(p1.x - dlx1 * rw, p1.y - dly1 * rw);
+ this._vset(lx1, ly1, 1);
+ this._vset(p1.x - dlx1 * rw, p1.y - dly1 * rw, -1);
} else {
let out = this._chooseBevel(p1.flags & PointFlags.PT_INNERBEVEL, p0, p1, -rw);
rx0 = out[0];
@@ -605,30 +665,30 @@ let graphicsAssembler = {
rx1 = out[2];
ry1 = out[3];
- this._vset(p1.x + dlx0 * lw, p1.y + dly0 * lw);
- this._vset(rx0, ry0);
+ this._vset(p1.x + dlx0 * lw, p1.y + dly0 * lw, 1);
+ this._vset(rx0, ry0, -1);
- this._vset(p1.x + dlx1 * lw, p1.y + dly1 * lw);
- this._vset(rx1, ry1);
+ this._vset(p1.x + dlx1 * lw, p1.y + dly1 * lw, 1);
+ this._vset(rx1, ry1, -1);
}
- },
+ }
- _vset (x, y) {
- let meshbuffer = _renderData.meshbuffer;
- let dataOffset = meshbuffer.vertexStart * 3;
+ _vset (x, y, distance = 0) {
+ let buffer = this._buffer;
+ let meshbuffer = buffer.meshbuffer;
+ let dataOffset = buffer.vertexStart * this.getVfmtFloatCount();
let vData = meshbuffer._vData;
let uintVData = meshbuffer._uintVData;
vData[dataOffset] = x;
vData[dataOffset+1] = y;
- uintVData[dataOffset+2] = _curColor;
+ uintVData[dataOffset+2] = this._curColor;
+ vData[dataOffset+3] = distance;
- meshbuffer.vertexStart ++;
+ buffer.vertexStart ++;
meshbuffer._dirty = true;
}
-};
-
-Graphics._assembler = graphicsAssembler;
+}
-module.exports = graphicsAssembler;
\ No newline at end of file
+Assembler.register(cc.Graphics, GraphicsAssembler);
diff --git a/cocos2d/core/renderer/webgl/assemblers/index.js b/cocos2d/core/renderer/webgl/assemblers/index.js
index 65a9b28071f..4ffbc1c08ae 100644
--- a/cocos2d/core/renderer/webgl/assemblers/index.js
+++ b/cocos2d/core/renderer/webgl/assemblers/index.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -23,6 +23,8 @@
THE SOFTWARE.
****************************************************************************/
+cc.assemblers = {};
+
require('./sprite');
require('./mask-assembler');
require('./graphics');
diff --git a/cocos2d/core/renderer/webgl/assemblers/label/2d/bmfont.js b/cocos2d/core/renderer/webgl/assemblers/label/2d/bmfont.js
new file mode 100644
index 00000000000..ac90d01bc1b
--- /dev/null
+++ b/cocos2d/core/renderer/webgl/assemblers/label/2d/bmfont.js
@@ -0,0 +1,180 @@
+/****************************************************************************
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import BmfontAssembler from '../../../../utils/label/bmfont';
+
+let _dataOffset = 0;
+
+export default class WebglBmfontAssembler extends BmfontAssembler {
+ initData () {
+ this._renderData.createFlexData(0, 4, 6, this.getVfmt());
+ }
+
+ _reserveQuads (comp, count) {
+ let verticesCount = count * 4;
+ let indicesCount = count * 6;
+
+ let flexBuffer = this._renderData._flexBuffer;
+ flexBuffer.reserve(verticesCount, indicesCount);
+ flexBuffer.used(verticesCount, indicesCount);
+
+ let iData = this._renderData.iDatas[0];
+
+ for (let i = 0, vid = 0, l = indicesCount; i < l; i += 6, vid += 4) {
+ iData[i] = vid;
+ iData[i + 1] = vid + 1;
+ iData[i + 2] = vid + 2;
+ iData[i + 3] = vid + 1;
+ iData[i + 4] = vid + 3;
+ iData[i + 5] = vid + 2;
+ }
+
+ _dataOffset = 0;
+ }
+
+ _quadsUpdated (comp) {
+ _dataOffset = 0;
+
+ let flexBuffer = this._renderData._flexBuffer;
+ flexBuffer.used(this.verticesCount, this.indicesCount);
+ }
+
+ _getColor (comp) {
+ return comp.node._color._val;
+ }
+
+ appendQuad (comp, texture, rect, rotated, x, y, scale) {
+ let renderData = this._renderData;
+ let verts = renderData.vDatas[0],
+ uintVerts = renderData.uintVDatas[0];
+
+ this.verticesCount += 4;
+ this.indicesCount = this.verticesCount / 2 * 3;
+
+ let texw = texture.width,
+ texh = texture.height,
+ rectWidth = rect.width,
+ rectHeight = rect.height,
+ color = this._getColor(comp);
+
+ let l, b, r, t;
+ let floatsPerVert = this.floatsPerVert;
+ // uvs
+ let uvDataOffset = _dataOffset + this.uvOffset;
+ if (!rotated) {
+ l = (rect.x) / texw;
+ r = (rect.x + rectWidth) / texw;
+ b = (rect.y + rectHeight) / texh;
+ t = (rect.y) / texh;
+
+ verts[uvDataOffset] = l;
+ verts[uvDataOffset + 1] = b;
+ uvDataOffset += floatsPerVert;
+ verts[uvDataOffset] = r;
+ verts[uvDataOffset + 1] = b;
+ uvDataOffset += floatsPerVert;
+ verts[uvDataOffset] = l;
+ verts[uvDataOffset + 1] = t;
+ uvDataOffset += floatsPerVert;
+ verts[uvDataOffset] = r;
+ verts[uvDataOffset + 1] = t;
+ } else {
+ l = (rect.x) / texw;
+ r = (rect.x + rectHeight) / texw;
+ b = (rect.y + rectWidth) / texh;
+ t = (rect.y) / texh;
+
+ verts[uvDataOffset] = l;
+ verts[uvDataOffset + 1] = t;
+ uvDataOffset += floatsPerVert;
+ verts[uvDataOffset] = l;
+ verts[uvDataOffset + 1] = b;
+ uvDataOffset += floatsPerVert;
+ verts[uvDataOffset] = r;
+ verts[uvDataOffset + 1] = t;
+ uvDataOffset += floatsPerVert;
+ verts[uvDataOffset] = r;
+ verts[uvDataOffset + 1] = b;
+ }
+
+
+ // positions
+ l = x;
+ r = x + rectWidth * scale;
+ b = y - rectHeight * scale;
+ t = y;
+
+ this.appendVerts(comp, _dataOffset, l, r, b, t);
+
+ // colors
+ let colorOffset = _dataOffset + this.colorOffset;
+ for (let i = 0; i < 4; i++) {
+ uintVerts[colorOffset] = color;
+ colorOffset += floatsPerVert;
+ }
+
+ _dataOffset += this.floatsPerVert * 4;
+ }
+
+ appendVerts (comp, offset, l, r, b, t) {
+ let local = this._local;
+ let floatsPerVert = this.floatsPerVert;
+
+ local[offset] = l;
+ local[offset + 1] = b;
+
+ offset += floatsPerVert;
+ local[offset] = r;
+ local[offset + 1] = b;
+
+ offset += floatsPerVert;
+ local[offset] = l;
+ local[offset + 1] = t;
+
+ offset += floatsPerVert;
+ local[offset] = r;
+ local[offset + 1] = t;
+ }
+
+ updateWorldVerts (comp) {
+ let node = comp.node;
+
+ let matrix = node._worldMatrix;
+ let matrixm = matrix.m,
+ a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
+ tx = matrixm[12], ty = matrixm[13];
+
+ let local = this._local;
+ let world = this._renderData.vDatas[0];
+ let floatsPerVert = this.floatsPerVert;
+ for (let offset = 0; offset < local.length; offset += floatsPerVert) {
+ let x = local[offset];
+ let y = local[offset + 1];
+ world[offset] = x * a + y * c + tx;
+ world[offset+1] = x * b + y * d + ty;
+ }
+ }
+}
+
diff --git a/cocos2d/core/load-pipeline/utils.js b/cocos2d/core/renderer/webgl/assemblers/label/2d/letter.js
similarity index 62%
rename from cocos2d/core/load-pipeline/utils.js
rename to cocos2d/core/renderer/webgl/assemblers/label/2d/letter.js
index 0821ff47523..08ac188846a 100644
--- a/cocos2d/core/load-pipeline/utils.js
+++ b/cocos2d/core/renderer/webgl/assemblers/label/2d/letter.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -23,29 +23,25 @@
THE SOFTWARE.
****************************************************************************/
-var _noCacheRex = /\?/;
-
-module.exports = {
- //isUrlCrossOrigin: function (url) {
- // if (!url) {
- // cc.log('invalid URL');
- // return false;
- // }
- // var startIndex = url.indexOf('://');
- // if (startIndex === -1)
- // return false;
- //
- // var endIndex = url.indexOf('/', startIndex + 3);
- // var urlOrigin = (endIndex === -1) ? url : url.substring(0, endIndex);
- // return urlOrigin !== location.origin;
- //},
- urlAppendTimestamp: function (url) {
- if (cc.game.config['noCache'] && typeof url === 'string') {
- if (_noCacheRex.test(url))
- url += '&_t=' + (new Date() - 0);
- else
- url += '?_t=' + (new Date() - 0);
- }
- return url;
+const js = require('../../../../../platform/js');
+const WebglBmfontAssembler = require('./bmfont');
+const LetterFontAssembler = require('../../../../utils/label/letter-font');
+const WHITE = cc.color(255, 255, 255, 255);
+
+export default class WebglLetterFontAssembler extends LetterFontAssembler {
+ createData (comp) {
+ return comp.requestRenderData();
+ }
+
+ _getColor (comp) {
+ WHITE._fastSetA(comp.node._color.a);
+ return WHITE._val;
}
-};
+
+ updateColor (comp) {
+ let color = this._getColor(comp);
+
+ super.updateColor(comp, color);
+ }
+}
+
diff --git a/cocos2d/core/renderer/webgl/assemblers/label/2d/nativeTTF.js b/cocos2d/core/renderer/webgl/assemblers/label/2d/nativeTTF.js
new file mode 100644
index 00000000000..954d631b9f8
--- /dev/null
+++ b/cocos2d/core/renderer/webgl/assemblers/label/2d/nativeTTF.js
@@ -0,0 +1,384 @@
+
+import MaterialVariant from '../../../../../assets/material/material-variant';
+
+const Label = require('../../../../../components/CCLabel');
+const LabelShadow = require('../../../../../components/CCLabelShadow');
+const LabelOutline = require('../../../../../components/CCLabelOutline');
+const Material = require('../../../../../assets/material/CCMaterial');
+
+
+
+const UPDATE_CONTENT = 1 << 0;
+const UPDATE_FONT = 1 << 1;
+const UPDATE_EFFECT = 1 << 2;
+
+export default class NativeTTF {
+
+
+ init(comp) {
+ this.labelMaterial = null;
+ this._label = this._renderComp = comp;
+ renderer.CustomAssembler.prototype.ctor.call(this);
+ comp.node._proxy.setAssembler(this);
+ this._layout = new jsb.LabelRenderer();
+ this._layout.init();
+ this._cfg = new DataView(this._layout._cfg);
+ this._layoutInfo = new DataView(this._layout._layout);
+
+ this._cfgFields = jsb.LabelRenderer._cfgFields;
+ this._layoutFields = jsb.LabelRenderer._layoutFields;
+ this._layout.bindNodeProxy(comp.node._proxy);
+ this._bindMaterial(comp);
+ }
+
+
+ _setBufferFlag(dv, offset, size, type, flag){
+ if ( type == "int8" && size == 1) {
+ let v = dv.getInt8(offset);
+ dv.setInt8(offset, flag | v);
+ } else if(type == "int32" && size == 4) {
+ let v = dv.getInt32(offset, jsb.__isLittleEndian__);
+ dv.setInt32(offset, flag|v , jsb.__isLittleEndian__);
+ } else {
+ cc.warn("flag storage type should be int8/int32 only, type/size -> " + type+"/"+size + ".");
+ }
+ }
+
+ _updateCfgFlag(flag) {
+ let field = this._cfgFields.updateFlags;
+ this._setBufferFlag(this._cfg, field.offset, field.size, field.type, flag);
+ }
+
+ _setBufferValue(dv, offset, size, type, value) {
+ if(type == "float" && size == 4) {
+ dv.setFloat32(offset, value, jsb.__isLittleEndian__);
+ } else if(type == "int32" && size == 4) {
+ dv.setInt32(offset, value, jsb.__isLittleEndian__);
+ } else if (type == "bool" && size == 1) {
+ dv.setInt8(offset, !!value ? 1 : 0, jsb.__isLittleEndian__);
+ } else if(type == "Color4B" && size == 4) {
+ dv.setUint8(offset, value.r);
+ dv.setUint8(offset + 1, value.g);
+ dv.setUint8(offset + 2, value.b);
+ dv.setUint8(offset + 3, value.a);
+ } else if(type == "int8" && size == 1) {
+ dv.setUint8(offset, value);
+ } else {
+ cc.warn("dont know how to set value to buffer, type/size -> " + type+"/"+size + ".");
+ }
+ }
+
+ _setFieldValue(dv, desc, field_name, value) {
+ let field = desc[field_name];
+ this._setBufferValue(dv, field.offset, field.size, field.type, value);
+ }
+
+ _getBufferValue(dv, offset, size, type) {
+ if(type == "float" && size == 4) {
+ return dv.getFloat32(offset, jsb.__isLittleEndian__);
+ } else if(type == "int32" && size == 4) {
+ return dv.getInt32(offset, jsb.__isLittleEndian__);
+ } else if (type == "bool" && size == 1) {
+ return dv.getInt8(offset, jsb.__isLittleEndian__) != 0;
+ } else if(type == "Color4B" && size == 4) {
+ let r = dv.getUint8(offset);
+ let g = dv.getUint8(offset + 1);
+ let b = dv.getUint8(offset + 2);
+ let a = dv.getUint8(offset + 3);
+ return {r, g, b, a};
+ } else if(type == "int8" && size == 1) {
+ return dv.getUint8(offset);
+ } else {
+ cc.warn("dont know how to get value from buffer, type/size -> " + type+"/"+size + ".");
+ return undefined;
+ }
+ }
+
+ _getFieldValue(dv, desc, field_name) {
+ let field = desc[field_name];
+ return this._getBufferValue(dv, field.offset, field.size, field.type);
+ }
+
+ _getLayoutValue(field_name) {
+ return this._getFieldValue(this._layoutInfo, this._layoutFields, field_name);
+ }
+
+ _setLayoutValue(field_name, value) {
+ return this._setFieldValue(this._layoutInfo, this._layoutFields, field_name, value);
+ }
+
+ _updateCfgFlag_Content() {
+ this._updateCfgFlag(UPDATE_CONTENT);
+ }
+
+ _updateCfgFlag_Font() {
+ this._updateCfgFlag(UPDATE_FONT);
+ }
+
+ _colorEqual(a, b) {
+ return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a;
+ }
+
+ _colorToObj(r, g, b, a) {
+ return {r, g, b, a};
+ }
+
+ setString(str)
+ {
+ if(str != this._layout.string) {
+ this._layout.string = str;
+ this._updateCfgFlag_Content();
+ }
+ }
+
+ setFontPath(path) {
+ if(path != this._layout.fontPath) {
+ this._layout.fontPath = path;
+ this._updateCfgFlag_Font();
+ }
+ }
+
+ setFontSize(fontSize, fontSizeRetina)
+ {
+ let oldfontsize = this._getFieldValue(this._cfg, this._cfgFields, "fontSize");
+ if(oldfontsize != fontSize) {
+ this._setFieldValue(this._cfg, this._cfgFields, "fontSize", fontSize);
+ this._setFieldValue(this._cfg, this._cfgFields, "fontSizeRetina", fontSizeRetina);
+ this._updateCfgFlag_Font();
+ }
+ }
+
+ setOutline(outline) {
+ let oldOutline = this._getLayoutValue("outlineSize");
+ if((oldOutline > 0) != (outline > 0)) {
+ this._updateCfgFlag_Font();
+ }
+ if(oldOutline != outline) {
+ this._updateCfgFlag_Content();
+ this._setLayoutValue("outlineSize", outline);
+ }
+ }
+
+ setOutlineColor(color) {
+ let oldColor = this._getLayoutValue( "outlineColor");
+ if(!this._colorEqual(oldColor, color)) {
+ this._setLayoutValue("outlineColor", color);
+ this._updateCfgFlag_Content();
+ }
+ }
+
+ setLineHeight(lineHeight) {
+ let oldLineHeight = this._getLayoutValue("lineHeight");
+ if(oldLineHeight != lineHeight) {
+ this._setLayoutValue("lineHeight", lineHeight);
+ this._updateCfgFlag_Content();
+ }
+ }
+
+ setOverFlow(overflow) {
+ let oldValue = this._getLayoutValue("overflow");
+ if(oldValue != overflow) {
+ this._setLayoutValue("overflow", overflow);
+ this._updateCfgFlag_Content();
+ }
+ }
+
+ setEnableWrap(value) {
+ let oldValue = this._getLayoutValue("wrap");
+ if(oldValue != value) {
+ this._setLayoutValue("wrap", value);
+ this._updateCfgFlag_Content();
+ }
+ }
+
+ setVerticalAlign(value) {
+ let oldValue = this._getLayoutValue("valign");
+ if(oldValue != value) {
+ this._setLayoutValue("valign", value);
+ this._updateCfgFlag_Content();
+ }
+ }
+
+ setHorizontalAlign(value) {
+ let oldValue = this._getLayoutValue("halign");
+ if(oldValue != value) {
+ this._setLayoutValue("halign", value);
+ this._updateCfgFlag_Content();
+ }
+ }
+
+ setContentSize(width, height) {
+ let oldWidth = this._getLayoutValue("width");
+ let oldHeight = this._getLayoutValue("height");
+ if(oldWidth != width || oldHeight != height) {
+ this._setLayoutValue("height", height);
+ this._setLayoutValue("width", width);
+ this._updateCfgFlag_Content();
+ }
+ }
+
+ setAnchorPoint(x, y) {
+ let oldX = this._getLayoutValue("anchorX");
+ let oldY = this._getLayoutValue("anchorY");
+ if(oldX != x || oldY != y) {
+ this._setLayoutValue("anchorX", x);
+ this._setLayoutValue("anchorY", y);
+ this._updateCfgFlag_Content();
+ }
+ }
+
+ setColor(color) {
+ let oldColor = this._getLayoutValue("color");
+ if(!this._colorEqual(oldColor, color)) {
+ this._setLayoutValue("color", color);
+ this._updateCfgFlag_Content();
+ }
+ }
+
+ setShadow( x, y, blur) {
+ let oldBlur = this._getLayoutValue("shadowBlur");
+ let oldX = this._getLayoutValue("shadowX");
+ let oldY = this._getLayoutValue("shadowY");
+ if((oldBlur > 0) != (blur > 0)) {
+ this._updateCfgFlag_Font();
+ }
+ let updateContent = false;
+ if(oldBlur != blur) {
+ this._setLayoutValue("shadowBlur", blur);
+ updateContent = true;
+ }
+ if(oldX != x) {
+ this._setLayoutValue("shadowX", x);
+ updateContent = true;
+ }
+ if(oldY != y) {
+ this._setLayoutValue("shadowY", y);
+ updateContent = true;
+ }
+ if(updateContent) {
+ this._updateCfgFlag_Content();
+ }
+ }
+
+ setShadowColor(color) {
+ let oldColor = this._getLayoutValue("shadowColor");
+ if(!this._colorEqual(oldColor, color)) {
+ this._setLayoutValue("shadowColor", color);
+ this._updateCfgFlag_Content();
+ }
+ }
+
+ setItalic(enabled) {
+ let oldItalic = this._getLayoutValue("italic");
+ if(oldItalic!=enabled) {
+ this._setLayoutValue("italic", enabled);
+ this._updateCfgFlag_Content();
+ }
+ }
+
+ setBold(bold) {
+ let oldBold = this._getLayoutValue("bold");
+ if(oldBold!=bold) {
+ this._setLayoutValue("bold", bold);
+ this._updateCfgFlag_Content();
+ this._updateCfgFlag_Font(); //enable sdf
+ }
+ }
+
+ setUnderline(underline)
+ {
+ let oldBold = this._getLayoutValue("underline");
+ if(oldBold != underline) {
+ this._setLayoutValue("underline", underline);
+ this._updateCfgFlag_Content();
+ }
+ }
+
+ setSpacingX(x) {
+ let oldX = this._getLayoutValue("spaceX");
+ if(oldX != x && typeof x == "number" && ! isNaN(x)) {
+ this._setLayoutValue("spaceX", x);
+ this._updateCfgFlag_Content();
+ }
+ }
+
+ updateRenderData(comp) {
+
+ if (!comp._vertsDirty) return;
+
+ if (comp.font && comp.font.nativeUrl) {
+ this.setFontPath(cc.assetManager.cacheManager.getCache(comp.font.nativeUrl) || comp.font.nativeUrl);
+ }
+ let layout = this._layout;
+ let c = comp.node.color;
+ let node = comp.node;
+ let retinaSize = comp.fontSize;
+
+ this.setString(comp.string);
+ this.setFontSize(comp.fontSize, retinaSize / 72 * comp.fontSize);
+ this.setLineHeight(comp.lineHeight);
+ this.setEnableWrap(comp.enableWrapText);
+ this.setItalic(comp.enableItalic);
+ this.setUnderline(comp.enableUnderline);
+ this.setBold(comp.enableBold);
+ this.setOverFlow(comp.overflow);
+ this.setVerticalAlign(comp.verticalAlign);
+ this.setHorizontalAlign(comp.horizontalAlign);
+ this.setSpacingX(comp.spacingX);
+ this.setContentSize(node.getContentSize().width, node.getContentSize().height);
+ this.setAnchorPoint(node.anchorX, node.anchorY);
+ this.setColor(this._colorToObj(c.getR(), c.getG(), c.getB(), Math.ceil(c.getA() * node.opacity / 255)));
+
+
+ let shadow = node.getComponent(cc.LabelShadow);
+ if (shadow && shadow.enabled) {
+ let shadowColor = shadow.color;
+ this.setShadow(shadow.offset.x, shadow.offset.y, shadow.blur);
+ this.setShadowColor(this._colorToObj(shadowColor.getR(), shadowColor.getG(), shadowColor.getB(), Math.ceil(shadowColor.getA() * node.opacity / 255)));
+ } else {
+ this.setShadow(0, 0, -1);
+ }
+
+ this._updateTTFMaterial(comp);
+
+ layout.render();
+ //comp._vertsDirty = false;
+ }
+
+ _bindMaterial(comp) {
+ let material = this.labelMaterial;
+ if(!material) {
+ material = MaterialVariant.createWithBuiltin("2d-label", comp);
+ this.labelMaterial = material;
+ }
+ return material;
+ }
+
+ _updateTTFMaterial(comp) {
+ let material = this._bindMaterial(comp)
+ let node = this._label.node;
+ let layout = this._layout;
+ let outline = node.getComponent(cc.LabelOutline);
+ let outlineSize = 0;
+ if (outline && outline.enabled && outline.width > 0) {
+ outlineSize = Math.max(Math.min(outline.width / 10, 0.4), 0.1);
+ let c = outline.color;
+ this.setOutlineColor(this._colorToObj(c.getR(), c.getG(), c.getB(), Math.ceil(c.getA() * node.opacity / 255)));
+ }
+ this.setOutline(outlineSize);
+ material.define('CC_USE_MODEL', true);
+ material.define('USE_TEXTURE_ALPHAONLY', true);
+ material.define('USE_SDF', outlineSize > 0.0 || comp.enableBold );
+ material.define('USE_SDF_EXTEND', comp.enableBold ? 1 : 0);
+ if (material.getDefine('CC_SUPPORT_standard_derivatives') !== undefined && cc.sys.glExtension('OES_standard_derivatives')) {
+ material.define('CC_SUPPORT_standard_derivatives', true);
+ }
+ layout.setEffect(material.effect._nativeObj);
+ }
+
+ fillBuffers (comp, renderer) {
+ this._layout.render();
+ }
+ getVfmt() {
+ }
+}
\ No newline at end of file
diff --git a/cocos2d/core/renderer/webgl/assemblers/label/2d/ttf.js b/cocos2d/core/renderer/webgl/assemblers/label/2d/ttf.js
new file mode 100644
index 00000000000..e0734401286
--- /dev/null
+++ b/cocos2d/core/renderer/webgl/assemblers/label/2d/ttf.js
@@ -0,0 +1,101 @@
+/****************************************************************************
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import TTFAssembler from '../../../../utils/label/ttf';
+
+const LabelShadow = require('../../../../../components/CCLabelShadow');
+const WHITE = cc.color(255, 255, 255, 255);
+
+export default class WebglTTFAssembler extends TTFAssembler {
+ updateUVs (comp) {
+ let verts = this._renderData.vDatas[0];
+ let uv = comp._frame.uv;
+ let uvOffset = this.uvOffset;
+ let floatsPerVert = this.floatsPerVert;
+ for (let i = 0; i < 4; i++) {
+ let srcOffset = i * 2;
+ let dstOffset = floatsPerVert * i + uvOffset;
+ verts[dstOffset] = uv[srcOffset];
+ verts[dstOffset + 1] = uv[srcOffset + 1];
+ }
+ }
+
+ updateColor (comp) {
+ WHITE._fastSetA(comp.node._color.a);
+ let color = WHITE._val;
+
+ super.updateColor(comp, color);
+ }
+
+ updateVerts (comp) {
+ let node = comp.node,
+ canvasWidth = comp._ttfTexture.width,
+ canvasHeight = comp._ttfTexture.height,
+ appx = node.anchorX * node.width,
+ appy = node.anchorY * node.height;
+
+ let shadow = LabelShadow && comp.getComponent(LabelShadow);
+ if (shadow && shadow._enabled) {
+ // adapt size changed caused by shadow
+ let offsetX = (canvasWidth - node.width) / 2;
+ let offsetY = (canvasHeight - node.height) / 2;
+
+ let shadowOffset = shadow.offset;
+ if (-shadowOffset.x > offsetX) {
+ // expand to left
+ appx += (canvasWidth - node.width);
+ }
+ else if (offsetX > shadowOffset.x) {
+ // expand to left and right
+ appx += (offsetX - shadowOffset.x);
+ }
+ else {
+ // expand to right, no need to change render position
+ }
+
+ if (-shadowOffset.y > offsetY) {
+ // expand to top
+ appy += (canvasHeight - node.height);
+ }
+ else if (offsetY > shadowOffset.y) {
+ // expand to top and bottom
+ appy += (offsetY - shadowOffset.y);
+ }
+ else {
+ // expand to bottom, no need to change render position
+ }
+ }
+
+ let local = this._local;
+ local[0] = -appx;
+ local[1] = -appy;
+ local[2] = canvasWidth - appx;
+ local[3] = canvasHeight - appy;
+
+ this.updateUVs(comp);
+ this.updateWorldVerts(comp);
+ }
+}
+
diff --git a/cocos2d/core/renderer/webgl/assemblers/label/3d/bmfont.js b/cocos2d/core/renderer/webgl/assemblers/label/3d/bmfont.js
new file mode 100644
index 00000000000..683ec14fc1d
--- /dev/null
+++ b/cocos2d/core/renderer/webgl/assemblers/label/3d/bmfont.js
@@ -0,0 +1,53 @@
+/****************************************************************************
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import Vec3 from '../../../../../value-types/vec3';
+const Assembler3D = require('../../../../assembler-3d');
+const WebglBmfontAssembler = require('../2d/bmfont');
+
+const vec3_temp_local = new Vec3();
+const vec3_temp_world = new Vec3();
+
+export default class WebglBmfontAssembler3D extends WebglBmfontAssembler {
+
+}
+
+cc.js.mixin(WebglBmfontAssembler3D.prototype, Assembler3D, {
+ updateWorldVerts (comp) {
+ let matrix = comp.node._worldMatrix;
+ let local = this._local;
+ let world = this._renderData.vDatas[0];
+
+ let floatsPerVert = this.floatsPerVert;
+ for (let offset = 0; offset < world.length; offset += floatsPerVert) {
+ Vec3.set(vec3_temp_local, local[offset], local[offset+1], 0);
+ Vec3.transformMat4(vec3_temp_world, vec3_temp_local, matrix);
+
+ world[offset] = vec3_temp_world.x;
+ world[offset+1] = vec3_temp_world.y;
+ world[offset+2] = vec3_temp_world.z;
+ }
+ }
+});
diff --git a/cocos2d/core/renderer/webgl/assemblers/label/3d/letter.js b/cocos2d/core/renderer/webgl/assemblers/label/3d/letter.js
new file mode 100644
index 00000000000..224031ddfb9
--- /dev/null
+++ b/cocos2d/core/renderer/webgl/assemblers/label/3d/letter.js
@@ -0,0 +1,54 @@
+/****************************************************************************
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import Vec3 from '../../../../../value-types/vec3';
+const Assembler3D = require('../../../../assembler-3d');
+const WebglLetterFontAssembler = require('../2d/letter');
+
+const vec3_temp_local = new Vec3();
+const vec3_temp_world = new Vec3();
+
+export default class WebglLetterFontAssembler3D extends WebglLetterFontAssembler {
+
+}
+
+cc.js.mixin(WebglLetterFontAssembler3D.prototype, Assembler3D, {
+ updateWorldVerts (comp) {
+ let matrix = comp.node._worldMatrix;
+ let local = this._local;
+ let world = this._renderData.vDatas[0];
+
+ let floatsPerVert = this.floatsPerVert;
+ for (let offset = 0; offset < world.length; offset += floatsPerVert) {
+ Vec3.set(vec3_temp_local, local[offset], local[offset+1], 0);
+ Vec3.transformMat4(vec3_temp_world, vec3_temp_local, matrix);
+
+ world[offset] = vec3_temp_world.x;
+ world[offset+1] = vec3_temp_world.y;
+ world[offset+2] = vec3_temp_world.z;
+ }
+ }
+});
+
diff --git a/cocos2d/core/renderer/webgl/assemblers/label/3d/ttf.js b/cocos2d/core/renderer/webgl/assemblers/label/3d/ttf.js
new file mode 100644
index 00000000000..6f2947261b0
--- /dev/null
+++ b/cocos2d/core/renderer/webgl/assemblers/label/3d/ttf.js
@@ -0,0 +1,33 @@
+/****************************************************************************
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+const Assembler3D = require('../../../../assembler-3d');
+const WebglTTFAssembler = require('../2d/ttf');
+
+export default class WebglTTFAssembler3D extends WebglTTFAssembler {
+
+}
+
+cc.js.mixin(WebglTTFAssembler3D.prototype, Assembler3D);
diff --git a/cocos2d/core/renderer/webgl/assemblers/label/bmfont.js b/cocos2d/core/renderer/webgl/assemblers/label/bmfont.js
deleted file mode 100644
index c4b985ee3ca..00000000000
--- a/cocos2d/core/renderer/webgl/assemblers/label/bmfont.js
+++ /dev/null
@@ -1,116 +0,0 @@
-/****************************************************************************
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-const js = require('../../../../platform/js');
-const bmfontUtls = require('../../../utils/label/bmfont');
-
-module.exports = js.addon({
- createData (comp) {
- return comp.requestRenderData();
- },
-
- fillBuffers (comp, renderer) {
- let node = comp.node,
- renderData = comp._renderData,
- data = renderData._data,
- color = node.color._val;
-
- let matrix = node._worldMatrix,
- a = matrix.m00, b = matrix.m01, c = matrix.m04, d = matrix.m05,
- tx = matrix.m12, ty = matrix.m13;
-
- let buffer = renderer._quadBuffer,
- vertexOffset = buffer.byteOffset >> 2;
-
- let vertexCount = renderData.vertexCount;
- buffer.request(vertexCount, renderData.indiceCount);
-
- // buffer data may be realloc, need get reference after request.
- let vbuf = buffer._vData;
-
- for (let i = 0; i < vertexCount; i++) {
- let vert = data[i];
- vbuf[vertexOffset++] = vert.x * a + vert.y * c + tx;
- vbuf[vertexOffset++] = vert.x * b + vert.y * d + ty;
- vbuf[vertexOffset++] = vert.u;
- vbuf[vertexOffset++] = vert.v;
- }
- },
-
- appendQuad (renderData, texture, rect, rotated, x, y, scale) {
- let dataOffset = renderData.dataLength;
-
- renderData.dataLength += 4;
- renderData.vertexCount = renderData.dataLength;
- renderData.indiceCount = renderData.dataLength / 2 * 3;
-
- let data = renderData._data;
- let texw = texture.width,
- texh = texture.height;
-
- let rectWidth = rect.width,
- rectHeight = rect.height;
-
- let l, b, r, t;
- if (!rotated) {
- l = (rect.x) / texw;
- r = (rect.x + rectWidth) / texw;
- b = (rect.y + rectHeight) / texh;
- t = (rect.y) / texh;
-
- data[dataOffset].u = l;
- data[dataOffset].v = b;
- data[dataOffset+1].u = r;
- data[dataOffset+1].v = b;
- data[dataOffset+2].u = l;
- data[dataOffset+2].v = t;
- data[dataOffset+3].u = r;
- data[dataOffset+3].v = t;
- } else {
- l = (rect.x) / texw;
- r = (rect.x + rectHeight) / texw;
- b = (rect.y + rectWidth) / texh;
- t = (rect.y) / texh;
-
- data[dataOffset].u = l;
- data[dataOffset].v = t;
- data[dataOffset+1].u = l;
- data[dataOffset+1].v = b;
- data[dataOffset+2].u = r;
- data[dataOffset+2].v = t;
- data[dataOffset+3].u = r;
- data[dataOffset+3].v = b;
- }
-
- data[dataOffset].x = x;
- data[dataOffset].y = y - rectHeight * scale;
- data[dataOffset+1].x = x + rectWidth * scale;
- data[dataOffset+1].y = y - rectHeight * scale;
- data[dataOffset+2].x = x;
- data[dataOffset+2].y = y;
- data[dataOffset+3].x = x + rectWidth * scale;
- data[dataOffset+3].y = y;
- },
-}, bmfontUtls);
diff --git a/cocos2d/core/renderer/webgl/assemblers/label/index.js b/cocos2d/core/renderer/webgl/assemblers/label/index.js
index fe44c9af4d9..ad2d5110dc7 100644
--- a/cocos2d/core/renderer/webgl/assemblers/label/index.js
+++ b/cocos2d/core/renderer/webgl/assemblers/label/index.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -23,27 +23,76 @@
THE SOFTWARE.
****************************************************************************/
-const Label = require('../../../../components/CCLabel');
-const ttfAssembler = require('./ttf');
-const bmfontAssembler = require('./bmfont');
+import Assembler from '../../../assembler';
+import Label from '../../../../components/CCLabel';
-var labelAssembler = {
- getAssembler (comp) {
- let assembler = ttfAssembler;
-
- if (comp.font instanceof cc.BitmapFont) {
- assembler = bmfontAssembler;
+import TTF from './2d/ttf';
+import Bmfont from './2d/bmfont';
+import Letter from './2d/letter';
+
+import TTF3D from './3d/ttf';
+import Bmfont3D from './3d/bmfont';
+import Letter3D from './3d/letter';
+
+let NativeTTF = undefined;
+if(CC_JSB) {
+ NativeTTF = require("./2d/nativeTTF");
+}
+
+Label._canvasPool = {
+ pool: [],
+ get () {
+ let data = this.pool.pop();
+
+ if (!data) {
+ let canvas = document.createElement("canvas");
+ let context = canvas.getContext("2d");
+ data = {
+ canvas: canvas,
+ context: context
+ }
+
+ // default text info
+ context.textBaseline = 'alphabetic';
}
- return assembler;
+ return data;
},
-
- // Skip invalid labels (without own _assembler)
- updateRenderData (label) {
- return label.__allocedDatas;
+ put (canvas) {
+ if (this.pool.length >= 32) {
+ return;
+ }
+ this.pool.push(canvas);
}
};
-Label._assembler = labelAssembler;
+Assembler.register(cc.Label, {
+ getConstructor(label) {
+ let is3DNode = label.node.is3DNode;
+ let ctor = is3DNode ? TTF3D : TTF;
+
+ if (label.font instanceof cc.BitmapFont) {
+ ctor = is3DNode ? Bmfont3D : Bmfont;
+ } else if (label.cacheMode === Label.CacheMode.CHAR) {
+
+ if(CC_JSB && !is3DNode && !!jsb.LabelRenderer && label.font instanceof cc.TTFFont && label._useNativeTTF()){
+ ctor = NativeTTF;
+ } else if (cc.sys.platform === cc.sys.WECHAT_GAME_SUB) {
+ cc.warn('sorry, subdomain does not support CHAR mode currently!');
+ } else {
+ ctor = is3DNode ? Letter3D : Letter;
+ }
+ }
+
+ return ctor;
+ },
+
+ TTF,
+ Bmfont,
+ Letter,
-module.exports = labelAssembler;
\ No newline at end of file
+ TTF3D,
+ Bmfont3D,
+ Letter3D,
+ NativeTTF
+});
diff --git a/cocos2d/core/renderer/webgl/assemblers/label/ttf.js b/cocos2d/core/renderer/webgl/assemblers/label/ttf.js
deleted file mode 100644
index 0d980acdc10..00000000000
--- a/cocos2d/core/renderer/webgl/assemblers/label/ttf.js
+++ /dev/null
@@ -1,93 +0,0 @@
-/****************************************************************************
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-const js = require('../../../../platform/js');
-const ttfUtls = require('../../../utils/label/ttf');
-
-module.exports = js.addon({
- createData (comp) {
- let renderData = comp.requestRenderData();
-
- renderData.dataLength = 4;
- renderData.vertexCount = 4;
- renderData.indiceCount = 6;
-
- let data = renderData._data;
- data[0].u = 0;
- data[0].v = 1;
- data[1].u = 1;
- data[1].v = 1;
- data[2].u = 0;
- data[2].v = 0;
- data[3].u = 1;
- data[3].v = 0;
- return renderData;
- },
-
- fillBuffers (comp, renderer) {
- let data = comp._renderData._data,
- node = comp.node,
- matrix = node._worldMatrix,
- a = matrix.m00, b = matrix.m01, c = matrix.m04, d = matrix.m05,
- tx = matrix.m12, ty = matrix.m13;
-
- let buffer = renderer._quadBuffer,
- vertexOffset = buffer.byteOffset >> 2;
-
- buffer.request(4, 6);
-
- // buffer data may be realloc, need get reference after request.
- let vbuf = buffer._vData;
-
- // vertex
- for (let i = 0; i < 4; i++) {
- let vert = data[i];
- vbuf[vertexOffset++] = vert.x * a + vert.y * c + tx;
- vbuf[vertexOffset++] = vert.x * b + vert.y * d + ty;
- vbuf[vertexOffset++] = vert.u;
- vbuf[vertexOffset++] = vert.v;
- }
- },
-
- _updateVerts (comp) {
- let renderData = comp._renderData;
-
- let node = comp.node,
- width = node.width,
- height = node.height,
- appx = node.anchorX * width,
- appy = node.anchorY * height;
-
- let data = renderData._data;
- data[0].x = -appx;
- data[0].y = -appy;
- data[1].x = width - appx;
- data[1].y = -appy;
- data[2].x = -appx;
- data[2].y = height - appy;
- data[3].x = width - appx;
- data[3].y = height - appy;
- }
-}, ttfUtls);
diff --git a/cocos2d/core/renderer/webgl/assemblers/mask-assembler.js b/cocos2d/core/renderer/webgl/assemblers/mask-assembler.js
index f73ebd73dc4..8bf102ad7c5 100644
--- a/cocos2d/core/renderer/webgl/assemblers/mask-assembler.js
+++ b/cocos2d/core/renderer/webgl/assemblers/mask-assembler.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -23,122 +23,173 @@
THE SOFTWARE.
****************************************************************************/
-const StencilManager = require('../stencil-manager');
-const Node = require('../../../CCNode');
+import Assembler from '../../assembler';
+
const Mask = require('../../../components/CCMask');
-const Graphics = require('../../../graphics/graphics');
const RenderFlow = require('../../render-flow');
+const SimpleSpriteAssembler = require('./sprite/2d/simple');
+const GraphicsAssembler = require('./graphics');
+const gfx = require('../../../../renderer/gfx');
+const vfmtPos = require('../vertex-format').vfmtPos;
+
+// todo: 8 is least Stencil depth supported by webGL device, it could be adjusted to vendor implementation value
+let _maxLevel = 8;
+// Current mask
+let _maskStack = [];
+
+function getWriteMask () {
+ return 0x01 << (_maskStack.length - 1);
+}
-const spriteAssembler = require('./sprite/simple');
-const graphicsAssembler = require('./graphics');
-
-let _stencilMgr = StencilManager.sharedManager;
-// for nested mask, we might need multiple graphics component to avoid data conflict
-let _graphicsPool = [];
-let _graphicsUsing = [];
-
-function getGraphics () {
- let graphics = _graphicsPool.pop();
-
- if (!graphics) {
- let graphicsNode = new Node();
- graphics = graphicsNode.addComponent(Graphics);
- graphics._activateMaterial();
- graphics.lineWidth = 0;
- graphics.rect(0, 0, cc.visibleRect.width, cc.visibleRect.height);
- graphics.fill();
- graphicsAssembler.updateRenderData(graphics);
+function getStencilRef () {
+ let result = 0;
+ for (let i = 0; i < _maskStack.length; ++i) {
+ result += (0x01 << i);
}
- return graphics;
+ return result;
}
-let maskFrontAssembler = {
- updateRenderData (mask) {
- if (!mask._renderData) {
- if (mask._type === Mask.Type.IMAGE_STENCIL) {
- mask._renderData = spriteAssembler.createData(mask);
- }
- else {
- // for updateGraphics calculation
- mask._renderData = mask.requestRenderData();
- }
- }
- let renderData = mask._renderData;
+function applyStencil (material, func, failOp, ref, stencilMask, writeMask) {
+ let effect = material.effect;
+ let zFailOp = gfx.STENCIL_OP_KEEP,
+ zPassOp = gfx.STENCIL_OP_KEEP;
+ effect.setStencil(gfx.STENCIL_ENABLE, func, ref, stencilMask, failOp, zFailOp, zPassOp, writeMask);
+}
+
+
+function pushMask (mask) {
+ if (_maskStack.length + 1 > _maxLevel) {
+ cc.errorID(9000, _maxLevel);
+ }
+ _maskStack.push(mask);
+}
+
+function exitMask (mask, renderer) {
+ if (_maskStack.length === 0) {
+ cc.errorID(9001);
+ }
+ _maskStack.pop();
+ if (_maskStack.length === 0) {
+ renderer._flushMaterial(mask._exitMaterial);
+ }
+ else {
+ enableMask(renderer);
+ }
+}
+
+function applyClearMask (mask, renderer) {
+ let func = gfx.DS_FUNC_NEVER;
+ let ref = getWriteMask();
+ let stencilMask = ref;
+ let writeMask = ref;
+ let failOp = mask.inverted ? gfx.STENCIL_OP_REPLACE : gfx.STENCIL_OP_ZERO;
+
+ applyStencil(mask._clearMaterial, func, failOp, ref, stencilMask, writeMask);
+
+ let buffer = renderer.getBuffer('mesh', vfmtPos);
+ let offsetInfo = buffer.request(4, 6);
+ let indiceOffset = offsetInfo.indiceOffset,
+ vertexOffset = offsetInfo.byteOffset >> 2,
+ vertexId = offsetInfo.vertexOffset,
+ vbuf = buffer._vData,
+ ibuf = buffer._iData;
+
+ vbuf[vertexOffset++] = -1;
+ vbuf[vertexOffset++] = -1;
+ vbuf[vertexOffset++] = -1;
+ vbuf[vertexOffset++] = 1;
+ vbuf[vertexOffset++] = 1;
+ vbuf[vertexOffset++] = 1;
+ vbuf[vertexOffset++] = 1;
+ vbuf[vertexOffset++] = -1;
+
+ ibuf[indiceOffset++] = vertexId;
+ ibuf[indiceOffset++] = vertexId + 3;
+ ibuf[indiceOffset++] = vertexId + 1;
+ ibuf[indiceOffset++] = vertexId + 1;
+ ibuf[indiceOffset++] = vertexId + 3;
+ ibuf[indiceOffset++] = vertexId + 2;
+
+ renderer.node = renderer._dummyNode;
+ renderer.material = mask._clearMaterial;
+ renderer._flush();
+}
+function applyAreaMask (mask, renderer) {
+ let func = gfx.DS_FUNC_NEVER;
+ let ref = getWriteMask();
+ let stencilMask = ref;
+ let writeMask = ref;
+ let failOp = mask.inverted ? gfx.STENCIL_OP_ZERO : gfx.STENCIL_OP_REPLACE;
+
+ applyStencil(mask._materials[0], func, failOp, ref, stencilMask, writeMask);
+
+ // vertex buffer
+ renderer.material = mask._materials[0];
+
+ if (mask._type === Mask.Type.IMAGE_STENCIL) {
+ renderer.node = renderer._dummyNode;
+ SimpleSpriteAssembler.prototype.fillBuffers.call(mask._assembler, mask, renderer);
+ renderer._flush();
+ }
+ else {
+ renderer.node = mask.node;
+ GraphicsAssembler.prototype.fillBuffers.call(mask._graphics._assembler, mask._graphics, renderer);
+ }
+}
+
+function enableMask (renderer) {
+ let func = gfx.DS_FUNC_EQUAL;
+ let failOp = gfx.STENCIL_OP_KEEP;
+ let ref = getStencilRef();
+ let stencilMask = ref;
+ let writeMask = getWriteMask();
+
+ let mask = _maskStack[_maskStack.length - 1];
+ applyStencil(mask._enableMaterial, func, failOp, ref, stencilMask, writeMask);
+ renderer._flushMaterial(mask._enableMaterial);
+}
+
+export class MaskAssembler extends SimpleSpriteAssembler {
+ updateRenderData (mask) {
if (mask._type === Mask.Type.IMAGE_STENCIL) {
if (mask.spriteFrame) {
- let size = mask.node._contentSize;
- let anchor = mask.node._anchorPoint;
- renderData.updateSizeNPivot(size.width, size.height, anchor.x, anchor.y);
- renderData.dataLength = 4;
- spriteAssembler.updateRenderData(mask);
- renderData.material = mask._material;
+ SimpleSpriteAssembler.prototype.updateRenderData.call(this, mask);
}
else {
- mask._material = null;
+ mask.setMaterial(0, null);
}
}
else {
- mask._graphics._material = mask._material;
- graphicsAssembler.updateRenderData(mask._graphics);
+ mask._graphics.setMaterial(0, mask._materials[0]);
+ GraphicsAssembler.prototype.updateRenderData.call(mask._graphics._assembler, mask._graphics, mask._graphics);
}
- },
+ }
fillBuffers (mask, renderer) {
// Invalid state
if (mask._type !== Mask.Type.IMAGE_STENCIL || mask.spriteFrame) {
// HACK: Must push mask after batch, so we can only put this logic in fillVertexBuffer or fillIndexBuffer
- _stencilMgr.pushMask(mask);
- _stencilMgr.clear();
-
- mask._clearGraphics = getGraphics();
- graphicsAssembler.fillBuffers(mask._clearGraphics, renderer);
+ pushMask(mask);
- _stencilMgr.enterLevel();
+ applyClearMask(mask, renderer);
+ applyAreaMask(mask, renderer);
- // vertex buffer
- renderer.node = mask.node;
- renderer.material = mask._material;
- if (mask._type === Mask.Type.IMAGE_STENCIL) {
- spriteAssembler.fillBuffers(mask, renderer);
- renderer._flush();
- }
- else {
- graphicsAssembler.fillBuffers(mask._graphics, renderer);
- }
+ enableMask(renderer);
}
mask.node._renderFlag |= RenderFlow.FLAG_UPDATE_RENDER_DATA;
}
-};
-let maskEndAssembler = {
- fillBuffers (mask, renderer) {
+ postFillBuffers (mask, renderer) {
// Invalid state
if (mask._type !== Mask.Type.IMAGE_STENCIL || mask.spriteFrame) {
// HACK: Must pop mask after batch, so we can only put this logic in fillBuffers
- _stencilMgr.exitMask();
-
- _graphicsUsing.push(mask._clearGraphics);
- mask._clearGraphics = null;
-
- // Clear graphics can only be recycled after the mask stack exits entirely.
- if (_stencilMgr.stage === StencilManager.Stage.DISABLED) {
- for (let i = 0; i < _graphicsUsing.length; i++) {
- _graphicsPool.push(_graphicsUsing[i]);
- }
- _graphicsUsing.length = 0;
- }
+ exitMask(mask, renderer);
}
mask.node._renderFlag |= RenderFlow.FLAG_UPDATE_RENDER_DATA;
}
};
-Mask._assembler = maskFrontAssembler;
-Mask._postAssembler = maskEndAssembler;
-
-module.exports = {
- front: maskFrontAssembler,
- end: maskEndAssembler
-}
\ No newline at end of file
+Assembler.register(Mask, MaskAssembler);
diff --git a/cocos2d/core/renderer/webgl/assemblers/motion-streak.js b/cocos2d/core/renderer/webgl/assemblers/motion-streak.js
index f3bade69cd3..d3161f8d475 100644
--- a/cocos2d/core/renderer/webgl/assemblers/motion-streak.js
+++ b/cocos2d/core/renderer/webgl/assemblers/motion-streak.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -23,9 +23,10 @@
THE SOFTWARE.
****************************************************************************/
+import Assembler2D from '../../assembler-2d';
+
const MotionStreak = require('../../../components/CCMotionStreak');
const RenderFlow = require('../../render-flow');
-const vfmtPosUvColor = require('../vertex-format').vfmtPosUvColor;
function Point (point, dir) {
this.point = point || cc.v2();
@@ -75,33 +76,19 @@ function computeMiter (miter, lineA, lineB, halfThick, maxMultiple) {
return halfThick * multiple;
}
-
-var motionStreakAssembler = {
- updateRenderData (comp) {
- let dt = cc.director.getDeltaTime();
- this.update(comp, dt);
-
- let renderData = comp._renderData;
- let size = comp.node._contentSize;
- let anchor = comp.node._anchorPoint;
- renderData.updateSizeNPivot(size.width, size.height, anchor.x, anchor.y);
- renderData.material = comp.getMaterial();
- },
+export default class MotionStreakAssembler extends Assembler2D {
+ initData () {
+ this._renderData.createFlexData(0, 16, (16 - 2) * 3);
+ }
update (comp, dt) {
- let renderData = comp._renderData;
- if (!renderData) {
- renderData = comp._renderData = comp.requestRenderData();
- }
-
if (CC_EDITOR && !comp.preview) return;
let stroke = comp._stroke / 2;
let node = comp.node;
- let matrix = node._worldMatrix;
- let a = matrix.m00, b = matrix.m01, c = matrix.m04, d = matrix.m05,
- tx = matrix.m12, ty = matrix.m13;
+ let matrix = node._worldMatrix.m;
+ let tx = matrix[12], ty = matrix[13];
let points = comp._points;
@@ -121,14 +108,14 @@ var motionStreakAssembler = {
cur.setPoint(tx, ty);
cur.time = comp._fadeTime + dt;
+
+ let verticesCount = 0;
+ let indicesCount = 0;
- renderData.dataLength = 0;
if (points.length < 2) {
return;
}
- let data = renderData._data;
-
let color = comp._color,
cr = color.r, cg = color.g, cb = color.b, ca = color.a;
@@ -137,7 +124,13 @@ var motionStreakAssembler = {
_vec2.normalizeSelf();
prev.setDir(_vec2.x, _vec2.y);
cur.setDir(_vec2.x, _vec2.y);
-
+
+ let flexBuffer = this._renderData._flexBuffer;
+ flexBuffer.reserve(points.length*2, (points.length-1)*6);
+ let vData = flexBuffer.vData;
+ let uintVData = flexBuffer.uintVData;
+ let vertsOffset = 5;
+
let fadeTime = comp._fadeTime;
let findLast = false;
for (let i = points.length - 1; i >=0 ; i--) {
@@ -167,61 +160,60 @@ var motionStreakAssembler = {
normal(_normal, dir);
- renderData.dataLength += 2;
let da = progress*ca;
let c = ((da<<24) >>> 0) + (cb<<16) + (cg<<8) + cr;
- let dataIndex = data.length - 1;
- data[dataIndex].x = point.x - _normal.x * stroke;
- data[dataIndex].y = point.y - _normal.y * stroke;
- data[dataIndex].u = 0;
- data[dataIndex].v = progress;
- data[dataIndex].color = c;
- dataIndex--;
- data[dataIndex].x = point.x + _normal.x * stroke;
- data[dataIndex].y = point.y + _normal.y * stroke;
- data[dataIndex].u = 1;
- data[dataIndex].v = progress;
- data[dataIndex].color = c;
+ let offset = verticesCount * vertsOffset;
+
+ vData[offset] = point.x + _normal.x * stroke;
+ vData[offset + 1] = point.y + _normal.y * stroke;
+ vData[offset + 2] = 1;
+ vData[offset + 3] = progress;
+ uintVData[offset + 4] = c;
+
+ offset += vertsOffset;
+
+ vData[offset] = point.x - _normal.x * stroke;
+ vData[offset + 1] = point.y - _normal.y * stroke;
+ vData[offset + 2] = 0;
+ vData[offset + 3] = progress;
+ uintVData[offset + 4] = c;
+
+ verticesCount += 2;
}
- renderData.vertexCount = renderData.dataLength;
- renderData.indiceCount = (renderData.vertexCount - 2)*3;
- },
+ indicesCount = verticesCount <= 2 ? 0 : (verticesCount - 2)*3;
+
+ flexBuffer.used(verticesCount, indicesCount);
+ }
fillBuffers (comp, renderer) {
- let node = comp.node,
- renderData = comp._renderData,
- data = renderData._data;
+ let { vData, usedVertices, usedIndices, usedVerticesFloats } = this._renderData._flexBuffer;
- let buffer = renderer.getBuffer('mesh', vfmtPosUvColor),
- vertexOffset = buffer.byteOffset >> 2,
- vertexCount = renderData.vertexCount;
-
- let indiceOffset = buffer.indiceOffset,
- vertexId = buffer.vertexOffset;
-
- buffer.request(vertexCount, renderData.indiceCount);
+ let buffer = renderer._meshBuffer;
+ let offsetInfo = buffer.request(usedVertices, usedIndices);
// buffer data may be realloc, need get reference after request.
- let vbuf = buffer._vData,
- ibuf = buffer._iData,
- uintbuf = buffer._uintVData;
-
- // vertex buffer
- let vert;
- for (let i = 0, l = renderData.vertexCount; i < l; i++) {
- vert = data[i];
- vbuf[vertexOffset++] = vert.x;
- vbuf[vertexOffset++] = vert.y;
- vbuf[vertexOffset++] = vert.u;
- vbuf[vertexOffset++] = vert.v;
- uintbuf[vertexOffset++] = vert.color;
+
+ // fill vertices
+ let vertexOffset = offsetInfo.byteOffset >> 2,
+ vbuf = buffer._vData;
+
+ if (vData.length + vertexOffset > vbuf.length) {
+ vbuf.set(vData.subarray(0, usedVerticesFloats), vertexOffset);
}
-
+ else {
+ vbuf.set(vData, vertexOffset);
+ }
+
+ // fill indices
+ let ibuf = buffer._iData,
+ indiceOffset = offsetInfo.indiceOffset,
+ vertexId = offsetInfo.vertexOffset;
+
// index buffer
- for (let i = 0, l = renderData.vertexCount; i < l; i += 2) {
+ for (let i = 0, l = usedVertices; i < l; i += 2) {
let start = vertexId + i;
ibuf[indiceOffset++] = start;
ibuf[indiceOffset++] = start + 2;
@@ -233,6 +225,6 @@ var motionStreakAssembler = {
comp.node._renderFlag |= RenderFlow.FLAG_UPDATE_RENDER_DATA;
}
-};
+}
-module.exports = MotionStreak._assembler = motionStreakAssembler;
+MotionStreakAssembler.register(MotionStreak, MotionStreakAssembler);
diff --git a/cocos2d/core/renderer/webgl/assemblers/sprite/2d/bar-filled.js b/cocos2d/core/renderer/webgl/assemblers/sprite/2d/bar-filled.js
new file mode 100644
index 00000000000..34d8af7855f
--- /dev/null
+++ b/cocos2d/core/renderer/webgl/assemblers/sprite/2d/bar-filled.js
@@ -0,0 +1,167 @@
+/****************************************************************************
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import Assembler2D from '../../../../assembler-2d';
+
+const Sprite = require('../../../../../components/CCSprite');
+const FillType = Sprite.FillType;
+
+export default class BarFilledAssembler extends Assembler2D {
+ updateRenderData (sprite) {
+ let frame = sprite._spriteFrame;
+ this.packToDynamicAtlas(sprite, frame);
+
+ if (!sprite._vertsDirty) {
+ return;
+ }
+
+ let fillStart = sprite._fillStart;
+ let fillRange = sprite._fillRange;
+
+ if (fillRange < 0) {
+ fillStart += fillRange;
+ fillRange = -fillRange;
+ }
+
+ fillRange = fillStart + fillRange;
+
+ fillStart = fillStart > 1.0 ? 1.0 : fillStart;
+ fillStart = fillStart < 0.0 ? 0.0 : fillStart;
+
+ fillRange = fillRange > 1.0 ? 1.0 : fillRange;
+ fillRange = fillRange < 0.0 ? 0.0 : fillRange;
+ fillRange = fillRange - fillStart;
+ fillRange = fillRange < 0 ? 0 : fillRange;
+
+ let fillEnd = fillStart + fillRange;
+ fillEnd = fillEnd > 1 ? 1 : fillEnd;
+
+ this.updateUVs(sprite, fillStart, fillEnd);
+ this.updateVerts(sprite, fillStart, fillEnd);
+
+ sprite._vertsDirty = false;
+ }
+
+ updateUVs (sprite, fillStart, fillEnd) {
+ let spriteFrame = sprite._spriteFrame;
+
+ //build uvs
+ let atlasWidth = spriteFrame._texture.width;
+ let atlasHeight = spriteFrame._texture.height;
+ let textureRect = spriteFrame._rect;
+ //uv computation should take spritesheet into account.
+ let ul, vb, ur, vt;
+ let quadUV0, quadUV1, quadUV2, quadUV3, quadUV4, quadUV5, quadUV6, quadUV7;
+ if (spriteFrame._rotated) {
+ ul = (textureRect.x) / atlasWidth;
+ vb = (textureRect.y + textureRect.width) / atlasHeight;
+ ur = (textureRect.x + textureRect.height) / atlasWidth;
+ vt = (textureRect.y) / atlasHeight;
+
+ quadUV0 = quadUV2 = ul;
+ quadUV4 = quadUV6 = ur;
+ quadUV3 = quadUV7 = vb;
+ quadUV1 = quadUV5 = vt;
+ }
+ else {
+ ul = (textureRect.x) / atlasWidth;
+ vb = (textureRect.y + textureRect.height) / atlasHeight;
+ ur = (textureRect.x + textureRect.width) / atlasWidth;
+ vt = (textureRect.y) / atlasHeight;
+
+ quadUV0 = quadUV4 = ul;
+ quadUV2 = quadUV6 = ur;
+ quadUV1 = quadUV3 = vb;
+ quadUV5 = quadUV7 = vt;
+ }
+
+ let verts = this._renderData.vDatas[0];
+ let uvOffset = this.uvOffset;
+ let floatsPerVert = this.floatsPerVert;
+ switch (sprite._fillType) {
+ case FillType.HORIZONTAL:
+ verts[uvOffset] = quadUV0 + (quadUV2 - quadUV0) * fillStart;
+ verts[uvOffset + 1] = quadUV1 + (quadUV3 - quadUV1) * fillStart;
+ verts[uvOffset + floatsPerVert] = quadUV0 + (quadUV2 - quadUV0) * fillEnd;
+ verts[uvOffset + floatsPerVert + 1] = quadUV1 + (quadUV3 - quadUV1) * fillEnd;
+ verts[uvOffset + floatsPerVert * 2] = quadUV4 + (quadUV6 - quadUV4) * fillStart;
+ verts[uvOffset + floatsPerVert * 2 + 1] = quadUV5 + (quadUV7 - quadUV5) * fillStart;
+ verts[uvOffset + floatsPerVert * 3] = quadUV4 + (quadUV6 - quadUV4) * fillEnd;
+ verts[uvOffset + floatsPerVert * 3 + 1] = quadUV5 + (quadUV7 - quadUV5) * fillEnd;
+ break;
+ case FillType.VERTICAL:
+ verts[uvOffset] = quadUV0 + (quadUV4 - quadUV0) * fillStart;
+ verts[uvOffset + 1] = quadUV1 + (quadUV5 - quadUV1) * fillStart;
+ verts[uvOffset + floatsPerVert] = quadUV2 + (quadUV6 - quadUV2) * fillStart;
+ verts[uvOffset + floatsPerVert + 1] = quadUV3 + (quadUV7 - quadUV3) * fillStart;
+ verts[uvOffset + floatsPerVert * 2] = quadUV0 + (quadUV4 - quadUV0) * fillEnd;
+ verts[uvOffset + floatsPerVert * 2 + 1] = quadUV1 + (quadUV5 - quadUV1) * fillEnd;
+ verts[uvOffset + floatsPerVert * 3] = quadUV2 + (quadUV6 - quadUV2) * fillEnd;
+ verts[uvOffset + floatsPerVert * 3 + 1] = quadUV3 + (quadUV7 - quadUV3) * fillEnd;
+ break;
+ default:
+ cc.errorID(2626);
+ break;
+ }
+ }
+
+ updateVerts (sprite, fillStart, fillEnd) {
+ let node = sprite.node,
+ width = node.width, height = node.height,
+ appx = node.anchorX * width, appy = node.anchorY * height;
+
+ let l = -appx, b = -appy,
+ r = width - appx, t = height - appy;
+
+ let progressStart, progressEnd;
+ switch (sprite._fillType) {
+ case FillType.HORIZONTAL:
+ progressStart = l + (r - l) * fillStart;
+ progressEnd = l + (r - l) * fillEnd;
+
+ l = progressStart;
+ r = progressEnd;
+ break;
+ case FillType.VERTICAL:
+ progressStart = b + (t - b) * fillStart;
+ progressEnd = b + (t - b) * fillEnd;
+
+ b = progressStart;
+ t = progressEnd;
+ break;
+ default:
+ cc.errorID(2626);
+ break;
+ }
+
+ let local = this._local;
+ local[0] = l;
+ local[1] = b;
+ local[2] = r;
+ local[3] = t;
+
+ this.updateWorldVerts(sprite);
+ }
+}
diff --git a/cocos2d/core/renderer/webgl/assemblers/sprite/2d/mesh.js b/cocos2d/core/renderer/webgl/assemblers/sprite/2d/mesh.js
new file mode 100644
index 00000000000..f49e9375ebf
--- /dev/null
+++ b/cocos2d/core/renderer/webgl/assemblers/sprite/2d/mesh.js
@@ -0,0 +1,138 @@
+/****************************************************************************
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import Assembler2D from '../../../../assembler-2d';
+
+export default class MeshSpriteAssembler extends Assembler2D {
+ initData (sprite) {
+ this._renderData.createFlexData(0, 4, 6, this.getVfmt());
+ }
+
+ updateRenderData (sprite) {
+ this.packToDynamicAtlas(sprite, sprite._spriteFrame);
+
+ let frame = sprite.spriteFrame;
+ if (frame) {
+ let vertices = frame.vertices;
+ if (vertices) {
+ this.verticesCount = vertices.x.length;
+ this.indicesCount = vertices.triangles.length;
+
+ let renderData = this._renderData;
+ let flexBuffer = renderData._flexBuffer;
+ if (flexBuffer.reserve(this.verticesCount, this.indicesCount)) {
+ this.updateColor(sprite);
+ sprite._vertsDirty = true;
+ }
+ flexBuffer.used(this.verticesCount, this.indicesCount);
+
+ this.updateIndices(vertices.triangles);
+
+ if (sprite._vertsDirty) {
+ this.updateUVs(sprite);
+ this.updateVerts(sprite);
+ this.updateWorldVerts(sprite);
+ sprite._vertsDirty = false;
+ }
+ }
+ }
+ }
+
+ updateIndices (triangles) {
+ this._renderData.iDatas[0].set(triangles);
+ }
+
+ updateUVs (sprite) {
+ let vertices = sprite.spriteFrame.vertices,
+ u = vertices.nu,
+ v = vertices.nv;
+
+ let uvOffset = this.uvOffset;
+ let floatsPerVert = this.floatsPerVert;
+ let verts = this._renderData.vDatas[0];
+ for (let i = 0; i < u.length; i++) {
+ let dstOffset = floatsPerVert * i + uvOffset;
+ verts[dstOffset] = u[i];
+ verts[dstOffset + 1] = v[i];
+ }
+ }
+
+ updateVerts (sprite) {
+ let node = sprite.node,
+ contentWidth = Math.abs(node.width),
+ contentHeight = Math.abs(node.height),
+ appx = node.anchorX * contentWidth,
+ appy = node.anchorY * contentHeight;
+
+ let frame = sprite.spriteFrame,
+ vertices = frame.vertices,
+ x = vertices.x,
+ y = vertices.y,
+ originalWidth = frame._originalSize.width,
+ originalHeight = frame._originalSize.height,
+ rectWidth = frame._rect.width,
+ rectHeight = frame._rect.height,
+ offsetX = frame._offset.x,
+ offsetY = frame._offset.y,
+ trimX = offsetX + (originalWidth - rectWidth) / 2,
+ trimY = offsetY + (originalHeight - rectHeight) / 2;
+
+ let scaleX = contentWidth / (sprite.trim ? rectWidth : originalWidth),
+ scaleY = contentHeight / (sprite.trim ? rectHeight : originalHeight);
+
+ let local = this._local;
+ if (!sprite.trim) {
+ for (let i = 0, l = x.length; i < l; i++) {
+ let offset = i * 2;
+ local[offset] = (x[i]) * scaleX - appx;
+ local[offset + 1] = (originalHeight - y[i]) * scaleY - appy;
+ }
+ }
+ else {
+ for (let i = 0, l = x.length; i < l; i++) {
+ let offset = i * 2;
+ local[offset] = (x[i] - trimX) * scaleX - appx;
+ local[offset + 1] = (originalHeight - y[i] - trimY) * scaleY - appy;
+ }
+ }
+ }
+
+ updateWorldVerts (sprite) {
+ let node = sprite.node;
+ let matrix = node._worldMatrix;
+ let matrixm = matrix.m;
+ let a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
+ tx = matrixm[12], ty = matrixm[13];
+ let local = this._local;
+ let world = this._renderData.vDatas[0];
+ let floatsPerVert = this.floatsPerVert;
+ for (let i = 0, l = this.verticesCount; i < l; i++) {
+ let lx = local[i*2];
+ let ly = local[i*2 + 1];
+ world[floatsPerVert * i] = lx * a + ly * c + tx;
+ world[floatsPerVert * i + 1] = lx * b + ly * d + ty;
+ }
+ }
+}
diff --git a/cocos2d/core/renderer/webgl/assemblers/sprite/2d/radial-filled.js b/cocos2d/core/renderer/webgl/assemblers/sprite/2d/radial-filled.js
new file mode 100644
index 00000000000..6bedde39c96
--- /dev/null
+++ b/cocos2d/core/renderer/webgl/assemblers/sprite/2d/radial-filled.js
@@ -0,0 +1,371 @@
+/****************************************************************************
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import Assembler2D from '../../../../assembler-2d';
+
+const PI_2 = Math.PI * 2;
+
+let _vertPos = [cc.v2(0, 0), cc.v2(0, 0), cc.v2(0, 0), cc.v2(0, 0)];
+let _vertices = [0, 0, 0, 0];
+let _uvs = [0, 0, 0, 0, 0, 0, 0, 0];
+let _intersectPoint_1 = [cc.v2(0, 0), cc.v2(0, 0), cc.v2(0, 0), cc.v2(0, 0)];
+let _intersectPoint_2 = [cc.v2(0, 0), cc.v2(0, 0), cc.v2(0, 0), cc.v2(0, 0)];
+let _center = cc.v2(0, 0);
+let _triangles = [];
+
+function _calcInsectedPoints (left, right, bottom, top, center, angle, intersectPoints) {
+ //left bottom, right, top
+ let sinAngle = Math.sin(angle);
+ let cosAngle = Math.cos(angle);
+ let tanAngle, cotAngle;
+ if (Math.cos(angle) !== 0) {
+ tanAngle = sinAngle / cosAngle;
+ //calculate right and left
+ if ((left - center.x) * cosAngle > 0) {
+ let yleft = center.y + tanAngle * (left - center.x);
+ intersectPoints[0].x = left;
+ intersectPoints[0].y = yleft;
+ }
+ if ((right - center.x) * cosAngle > 0) {
+ let yright = center.y + tanAngle * (right - center.x);
+
+ intersectPoints[2].x = right;
+ intersectPoints[2].y = yright;
+ }
+
+ }
+
+ if (Math.sin(angle) !== 0) {
+ cotAngle = cosAngle / sinAngle;
+ //calculate top and bottom
+ if ((top - center.y) * sinAngle > 0) {
+ let xtop = center.x + cotAngle * (top - center.y);
+ intersectPoints[3].x = xtop;
+ intersectPoints[3].y = top;
+ }
+ if ((bottom - center.y) * sinAngle > 0) {
+ let xbottom = center.x + cotAngle * (bottom - center.y);
+ intersectPoints[1].x = xbottom;
+ intersectPoints[1].y = bottom;
+ }
+
+ }
+}
+
+function _calculateVertices (sprite) {
+ let node = sprite.node,
+ width = node.width, height = node.height,
+ appx = node.anchorX * width, appy = node.anchorY * height;
+
+ let l = -appx, b = -appy,
+ r = width - appx, t = height - appy;
+
+ let vertices = _vertices;
+ vertices[0] = l;
+ vertices[1] = b;
+ vertices[2] = r;
+ vertices[3] = t;
+
+ let fillCenter = sprite._fillCenter,
+ cx = _center.x = Math.min(Math.max(0, fillCenter.x), 1) * (r - l) + l,
+ cy = _center.y = Math.min(Math.max(0, fillCenter.y), 1) * (t - b) + b;
+
+ _vertPos[0].x = _vertPos[3].x = l;
+ _vertPos[1].x = _vertPos[2].x = r;
+ _vertPos[0].y = _vertPos[1].y = b;
+ _vertPos[2].y = _vertPos[3].y = t;
+
+ _triangles.length = 0;
+ if (cx !== vertices[0]) {
+ _triangles[0] = [3, 0];
+ }
+ if (cx !== vertices[2]) {
+ _triangles[2] = [1, 2];
+ }
+ if (cy !== vertices[1]) {
+ _triangles[1] = [0, 1];
+ }
+ if (cy !== vertices[3]) {
+ _triangles[3] = [2, 3];
+ }
+}
+
+function _calculateUVs (spriteFrame) {
+ let atlasWidth = spriteFrame._texture.width;
+ let atlasHeight = spriteFrame._texture.height;
+ let textureRect = spriteFrame._rect;
+
+ let u0, u1, v0, v1;
+ let uvs = _uvs;
+
+ if (spriteFrame._rotated) {
+ u0 = (textureRect.x) / atlasWidth;
+ u1 = (textureRect.x + textureRect.height) / atlasWidth;
+
+ v0 = (textureRect.y) / atlasHeight;
+ v1 = (textureRect.y + textureRect.width) / atlasHeight;
+
+ uvs[0] = uvs[2] = u0;
+ uvs[4] = uvs[6] = u1;
+ uvs[3] = uvs[7] = v1;
+ uvs[1] = uvs[5] = v0;
+ }
+ else {
+ u0 = (textureRect.x) / atlasWidth;
+ u1 = (textureRect.x + textureRect.width) / atlasWidth;
+
+ v0 = (textureRect.y) / atlasHeight;
+ v1 = (textureRect.y + textureRect.height) / atlasHeight;
+
+ uvs[0] = uvs[4] = u0;
+ uvs[2] = uvs[6] = u1;
+ uvs[1] = uvs[3] = v1;
+ uvs[5] = uvs[7] = v0;
+ }
+}
+
+function _getVertAngle (start, end) {
+ let placementX, placementY;
+ placementX = end.x - start.x;
+ placementY = end.y - start.y;
+
+ if (placementX === 0 && placementY === 0) {
+ return undefined;
+ } else if (placementX === 0) {
+ if (placementY > 0) {
+ return Math.PI * 0.5;
+ } else {
+ return Math.PI * 1.5;
+ }
+ } else {
+ let angle = Math.atan(placementY / placementX);
+ if (placementX < 0) {
+ angle += Math.PI;
+ }
+
+ return angle;
+ }
+}
+
+export default class RadialFilledAssembler extends Assembler2D {
+ initData (sprite) {
+ this._renderData.createFlexData(0, 4, 6, this.getVfmt());
+ this.updateIndices();
+ }
+
+ updateRenderData (sprite) {
+ super.updateRenderData(sprite);
+
+ let frame = sprite.spriteFrame;
+ this.packToDynamicAtlas(sprite, frame);
+
+ if (sprite._vertsDirty) {
+ let fillStart = sprite._fillStart;
+ let fillRange = sprite._fillRange;
+ if (fillRange < 0) {
+ fillStart += fillRange;
+ fillRange = -fillRange;
+ }
+
+ //do round fill start [0,1), include 0, exclude 1
+ while (fillStart >= 1.0) fillStart -= 1.0;
+ while (fillStart < 0.0) fillStart += 1.0;
+
+ fillStart *= PI_2;
+ fillRange *= PI_2;
+
+ //build vertices
+ _calculateVertices(sprite);
+ //build uvs
+ _calculateUVs(frame);
+
+ _calcInsectedPoints(_vertices[0], _vertices[2], _vertices[1], _vertices[3], _center, fillStart, _intersectPoint_1);
+ _calcInsectedPoints(_vertices[0], _vertices[2], _vertices[1], _vertices[3], _center, fillStart + fillRange, _intersectPoint_2);
+
+ this.updateVerts(sprite, fillStart, fillRange);
+
+ sprite._vertsDirty = false;
+ }
+ }
+
+ updateVerts (sprite, fillStart, fillRange) {
+ let fillEnd = fillStart + fillRange;
+
+ let local = this._local;
+ local.length = 0;
+
+ let offset = 0;
+ let floatsPerTriangle = 3 * this.floatsPerVert;
+ for (let triangleIndex = 0; triangleIndex < 4; ++triangleIndex) {
+ let triangle = _triangles[triangleIndex];
+ if (!triangle) {
+ continue;
+ }
+ //all in
+ if (fillRange >= PI_2) {
+ local.length = offset + floatsPerTriangle;
+ this._generateTriangle(local, offset, _center, _vertPos[triangle[0]], _vertPos[triangle[1]]);
+ offset += floatsPerTriangle;
+ continue;
+ }
+ //test against
+ let startAngle = _getVertAngle(_center, _vertPos[triangle[0]]);
+ let endAngle = _getVertAngle(_center, _vertPos[triangle[1]]);
+ if (endAngle < startAngle) endAngle += PI_2;
+ startAngle -= PI_2;
+ endAngle -= PI_2;
+ //testing
+ for (let testIndex = 0; testIndex < 3; ++testIndex) {
+ if (startAngle >= fillEnd) {
+ //all out
+ } else if (startAngle >= fillStart) {
+ local.length = offset + floatsPerTriangle;
+ if (endAngle >= fillEnd) {
+ //startAngle to fillEnd
+ this._generateTriangle(local, offset, _center, _vertPos[triangle[0]], _intersectPoint_2[triangleIndex]);
+ } else {
+ //startAngle to endAngle
+ this._generateTriangle(local, offset, _center, _vertPos[triangle[0]], _vertPos[triangle[1]]);
+ }
+ offset += floatsPerTriangle;
+ } else {
+ //startAngle < fillStart
+ if (endAngle <= fillStart) {
+ //all out
+ } else if (endAngle <= fillEnd) {
+ local.length = offset + floatsPerTriangle;
+ //fillStart to endAngle
+ this._generateTriangle(local, offset, _center, _intersectPoint_1[triangleIndex], _vertPos[triangle[1]]);
+ offset += floatsPerTriangle;
+ } else {
+ local.length = offset + floatsPerTriangle;
+ //fillStart to fillEnd
+ this._generateTriangle(local, offset, _center, _intersectPoint_1[triangleIndex], _intersectPoint_2[triangleIndex]);
+ offset += floatsPerTriangle;
+ }
+ }
+ //add 2 * PI
+ startAngle += PI_2;
+ endAngle += PI_2;
+ }
+ }
+
+ this.allocWorldVerts(sprite);
+ this.updateWorldVerts(sprite);
+ }
+
+ allocWorldVerts(sprite) {
+ let color = sprite.node._color._val;
+ let renderData = this._renderData;
+ let floatsPerVert = this.floatsPerVert;
+
+ let local = this._local;
+ let verticesCount = local.length / floatsPerVert;
+ this.verticesCount = this.indicesCount = verticesCount;
+
+ let flexBuffer = renderData._flexBuffer;
+ if (flexBuffer.reserve(verticesCount, verticesCount)) {
+ this.updateIndices();
+ }
+ flexBuffer.used(this.verticesCount, this.indicesCount);
+
+ let verts = renderData.vDatas[0],
+ uintVerts = renderData.uintVDatas[0];
+
+ let uvOffset = this.uvOffset;
+ for (let offset = 0; offset < local.length; offset += floatsPerVert) {
+ let start = offset + uvOffset;
+ verts[start] = local[start];
+ verts[start + 1] = local[start + 1];
+ uintVerts[start + 2] = color;
+ }
+ }
+
+ updateIndices () {
+ let iData = this._renderData.iDatas[0];
+ for (let i = 0; i < iData.length; i ++) {
+ iData[i] = i;
+ }
+ }
+
+ updateWorldVerts (sprite) {
+ let node = sprite.node;
+
+ let matrix = node._worldMatrix;
+ let matrixm = matrix.m,
+ a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
+ tx = matrixm[12], ty = matrixm[13];
+
+ let local = this._local;
+ let world = this._renderData.vDatas[0];
+ let floatsPerVert = this.floatsPerVert;
+ for (let offset = 0; offset < local.length; offset += floatsPerVert) {
+ let x = local[offset];
+ let y = local[offset + 1];
+ world[offset] = x * a + y * c + tx;
+ world[offset+1] = x * b + y * d + ty;
+ }
+ }
+
+ _generateTriangle (verts, offset, vert0, vert1, vert2) {
+ let vertices = _vertices;
+ let v0x = vertices[0];
+ let v0y = vertices[1];
+ let v1x = vertices[2];
+ let v1y = vertices[3];
+
+ let floatsPerVert = this.floatsPerVert;
+ verts[offset] = vert0.x;
+ verts[offset + 1] = vert0.y;
+ verts[offset + floatsPerVert] = vert1.x;
+ verts[offset + floatsPerVert + 1] = vert1.y;
+ verts[offset + floatsPerVert*2] = vert2.x;
+ verts[offset + floatsPerVert*2 + 1] = vert2.y;
+
+ let uvOffset = this.uvOffset;
+ let progressX, progressY;
+ progressX = (vert0.x - v0x) / (v1x - v0x);
+ progressY = (vert0.y - v0y) / (v1y - v0y);
+ this._generateUV(progressX, progressY, verts, offset + uvOffset);
+
+ progressX = (vert1.x - v0x) / (v1x - v0x);
+ progressY = (vert1.y - v0y) / (v1y - v0y);
+ this._generateUV(progressX, progressY, verts, offset + floatsPerVert + uvOffset);
+
+ progressX = (vert2.x - v0x) / (v1x - v0x);
+ progressY = (vert2.y - v0y) / (v1y - v0y);
+ this._generateUV(progressX, progressY, verts, offset + floatsPerVert*2 + uvOffset);
+ }
+
+ _generateUV (progressX, progressY, verts, offset) {
+ let uvs = _uvs;
+ let px1 = uvs[0] + (uvs[2] - uvs[0]) * progressX;
+ let px2 = uvs[4] + (uvs[6] - uvs[4]) * progressX;
+ let py1 = uvs[1] + (uvs[3] - uvs[1]) * progressX;
+ let py2 = uvs[5] + (uvs[7] - uvs[5]) * progressX;
+ verts[offset] = px1 + (px2 - px1) * progressY;
+ verts[offset + 1] = py1 + (py2 - py1) * progressY;
+ }
+}
diff --git a/cocos2d/core/renderer/webgl/assemblers/sprite/2d/simple.js b/cocos2d/core/renderer/webgl/assemblers/sprite/2d/simple.js
new file mode 100644
index 00000000000..939e7b1c392
--- /dev/null
+++ b/cocos2d/core/renderer/webgl/assemblers/sprite/2d/simple.js
@@ -0,0 +1,86 @@
+/****************************************************************************
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import Assembler2D from '../../../../assembler-2d';
+
+export default class SimpleSpriteAssembler extends Assembler2D {
+ updateRenderData (sprite) {
+ this.packToDynamicAtlas(sprite, sprite._spriteFrame);
+
+ if (sprite._vertsDirty) {
+ this.updateUVs(sprite);
+ this.updateVerts(sprite);
+ sprite._vertsDirty = false;
+ }
+ }
+
+ updateUVs (sprite) {
+ let uv = sprite._spriteFrame.uv;
+ let uvOffset = this.uvOffset;
+ let floatsPerVert = this.floatsPerVert;
+ let verts = this._renderData.vDatas[0];
+ for (let i = 0; i < 4; i++) {
+ let srcOffset = i * 2;
+ let dstOffset = floatsPerVert * i + uvOffset;
+ verts[dstOffset] = uv[srcOffset];
+ verts[dstOffset + 1] = uv[srcOffset + 1];
+ }
+ }
+
+ updateVerts (sprite) {
+ let node = sprite.node,
+ cw = node.width, ch = node.height,
+ appx = node.anchorX * cw, appy = node.anchorY * ch,
+ l, b, r, t;
+ if (sprite.trim) {
+ l = -appx;
+ b = -appy;
+ r = cw - appx;
+ t = ch - appy;
+ }
+ else {
+ let frame = sprite.spriteFrame,
+ ow = frame._originalSize.width, oh = frame._originalSize.height,
+ rw = frame._rect.width, rh = frame._rect.height,
+ offset = frame._offset,
+ scaleX = cw / ow, scaleY = ch / oh;
+ let trimLeft = offset.x + (ow - rw) / 2;
+ let trimRight = offset.x - (ow - rw) / 2;
+ let trimBottom = offset.y + (oh - rh) / 2;
+ let trimTop = offset.y - (oh - rh) / 2;
+ l = trimLeft * scaleX - appx;
+ b = trimBottom * scaleY - appy;
+ r = cw + trimRight * scaleX - appx;
+ t = ch + trimTop * scaleY - appy;
+ }
+
+ let local = this._local;
+ local[0] = l;
+ local[1] = b;
+ local[2] = r;
+ local[3] = t;
+ this.updateWorldVerts(sprite);
+ }
+}
diff --git a/cocos2d/core/renderer/webgl/assemblers/sprite/2d/sliced.js b/cocos2d/core/renderer/webgl/assemblers/sprite/2d/sliced.js
new file mode 100644
index 00000000000..9013a9b05eb
--- /dev/null
+++ b/cocos2d/core/renderer/webgl/assemblers/sprite/2d/sliced.js
@@ -0,0 +1,139 @@
+/****************************************************************************
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ http://www.cocos.com
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import Assembler2D from '../../../../assembler-2d';
+
+export default class SlicedAssembler extends Assembler2D {
+ initData (sprite) {
+ if (this._renderData.meshCount > 0) return;
+ this._renderData.createData(0, this.verticesFloats, this.indicesCount);
+
+ let indices = this._renderData.iDatas[0];
+ let indexOffset = 0;
+ for (let r = 0; r < 3; ++r) {
+ for (let c = 0; c < 3; ++c) {
+ let start = r * 4 + c;
+ indices[indexOffset++] = start;
+ indices[indexOffset++] = start + 1;
+ indices[indexOffset++] = start + 4;
+ indices[indexOffset++] = start + 1;
+ indices[indexOffset++] = start + 5;
+ indices[indexOffset++] = start + 4;
+ }
+ }
+ }
+
+ initLocal () {
+ this._local = [];
+ this._local.length = 8;
+ }
+
+ updateRenderData (sprite) {
+ let frame = sprite._spriteFrame;
+ this.packToDynamicAtlas(sprite, frame);
+
+ if (sprite._vertsDirty) {
+ this.updateUVs(sprite);
+ this.updateVerts(sprite);
+ sprite._vertsDirty = false;
+ }
+ }
+
+ updateVerts (sprite) {
+ let node = sprite.node,
+ width = node.width, height = node.height,
+ appx = node.anchorX * width, appy = node.anchorY * height;
+
+ let frame = sprite.spriteFrame;
+ let leftWidth = frame.insetLeft;
+ let rightWidth = frame.insetRight;
+ let topHeight = frame.insetTop;
+ let bottomHeight = frame.insetBottom;
+
+ let sizableWidth = width - leftWidth - rightWidth;
+ let sizableHeight = height - topHeight - bottomHeight;
+ let xScale = width / (leftWidth + rightWidth);
+ let yScale = height / (topHeight + bottomHeight);
+ xScale = (isNaN(xScale) || xScale > 1) ? 1 : xScale;
+ yScale = (isNaN(yScale) || yScale > 1) ? 1 : yScale;
+ sizableWidth = sizableWidth < 0 ? 0 : sizableWidth;
+ sizableHeight = sizableHeight < 0 ? 0 : sizableHeight;
+
+ // update local
+ let local = this._local;
+ local[0] = -appx;
+ local[1] = -appy;
+ local[2] = leftWidth * xScale - appx;
+ local[3] = bottomHeight * yScale - appy;
+ local[4] = local[2] + sizableWidth;
+ local[5] = local[3] + sizableHeight;
+ local[6] = width - appx;
+ local[7] = height - appy;
+
+ this.updateWorldVerts(sprite);
+ }
+
+ updateUVs (sprite) {
+ let verts = this._renderData.vDatas[0];
+ let uvSliced = sprite.spriteFrame.uvSliced;
+ let uvOffset = this.uvOffset;
+ let floatsPerVert = this.floatsPerVert;
+ for (let row = 0; row < 4; ++row) {
+ for (let col = 0; col < 4; ++col) {
+ let vid = row * 4 + col;
+ let uv = uvSliced[vid];
+ let voffset = vid * floatsPerVert;
+ verts[voffset + uvOffset] = uv.u;
+ verts[voffset + uvOffset + 1] = uv.v;
+ }
+ }
+ }
+
+ updateWorldVerts (sprite) {
+ let matrix = sprite.node._worldMatrix;
+ let matrixm = matrix.m,
+ a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
+ tx = matrixm[12], ty = matrixm[13];
+
+ let local = this._local;
+ let world = this._renderData.vDatas[0];
+
+ let floatsPerVert = this.floatsPerVert;
+ for (let row = 0; row < 4; ++row) {
+ let localRowY = local[row * 2 + 1];
+ for (let col = 0; col < 4; ++col) {
+ let localColX = local[col * 2];
+ let worldIndex = (row * 4 + col) * floatsPerVert;
+ world[worldIndex] = localColX * a + localRowY * c + tx;
+ world[worldIndex + 1] = localColX * b + localRowY * d + ty;
+ }
+ }
+ }
+}
+
+Object.assign(SlicedAssembler.prototype, {
+ verticesCount: 16,
+ indicesCount: 54
+});
diff --git a/cocos2d/core/renderer/webgl/assemblers/sprite/2d/tiled.js b/cocos2d/core/renderer/webgl/assemblers/sprite/2d/tiled.js
new file mode 100644
index 00000000000..d7e080b79cd
--- /dev/null
+++ b/cocos2d/core/renderer/webgl/assemblers/sprite/2d/tiled.js
@@ -0,0 +1,357 @@
+/****************************************************************************
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import Assembler2D from '../../../../assembler-2d';
+
+export default class TiledAssembler extends Assembler2D {
+ initData (sprite) {
+ this.verticesCount = 0;
+ this.contentWidth = 0;
+ this.contentHeight = 0;
+ this.rectWidth = 0;
+ this.rectHeight = 0;
+ this.hRepeat = 0;
+ this.vRepeat = 0;
+ this.row = 0;
+ this.col = 0;
+
+ this._renderData.createFlexData(0, 4, 6, this.getVfmt());
+ this._updateIndices();
+ }
+
+ initLocal () {
+ this._local = { x: [], y: []};
+ }
+
+ _updateIndices () {
+ let iData = this._renderData.iDatas[0];
+ for (let i = 0, vid = 0, l = iData.length; i < l; i += 6, vid += 4) {
+ iData[i] = vid;
+ iData[i + 1] = vid + 1;
+ iData[i + 2] = vid + 2;
+ iData[i + 3] = vid + 1;
+ iData[i + 4] = vid + 3;
+ iData[i + 5] = vid + 2;
+ }
+ }
+
+ updateRenderData (sprite) {
+ let frame = sprite._spriteFrame;
+ this.packToDynamicAtlas(sprite, frame);
+
+ let node = sprite.node;
+
+ let contentWidth = this.contentWidth = Math.abs(node.width);
+ let contentHeight = this.contentHeight = Math.abs(node.height);
+ let rect = frame._rect;
+ let leftWidth = frame.insetLeft, rightWidth = frame.insetRight, centerWidth = rect.width - leftWidth - rightWidth,
+ topHeight = frame.insetTop, bottomHeight = frame.insetBottom, centerHeight = rect.height - topHeight - bottomHeight;
+ this.sizableWidth = contentWidth - leftWidth - rightWidth;
+ this.sizableHeight = contentHeight - topHeight - bottomHeight;
+ this.sizableWidth = this.sizableWidth > 0 ? this.sizableWidth : 0;
+ this.sizableHeight = this.sizableHeight > 0 ? this.sizableHeight : 0;
+ let hRepeat = this.hRepeat = centerWidth === 0 ? this.sizableWidth : this.sizableWidth / centerWidth;
+ let vRepeat = this.vRepeat = centerHeight === 0 ? this.sizableHeight : this.sizableHeight / centerHeight;
+ let row = this.row = Math.ceil(vRepeat + 2);
+ let col = this.col = Math.ceil(hRepeat + 2);
+
+ // update data property
+ let count = row * col;
+ this.verticesCount = count * 4;
+ this.indicesCount = count * 6;
+
+ let renderData = this._renderData;
+ let flexBuffer = renderData._flexBuffer;
+ if (flexBuffer.reserve(this.verticesCount, this.indicesCount)) {
+ this._updateIndices();
+ this.updateColor(sprite);
+ }
+ flexBuffer.used(this.verticesCount, this.indicesCount);
+
+ if (sprite._vertsDirty) {
+ this.updateUVs(sprite);
+ this.updateVerts(sprite);
+ sprite._vertsDirty = false;
+ }
+ }
+
+ updateVerts (sprite) {
+ let frame = sprite._spriteFrame;
+ let rect = frame._rect;
+ let node = sprite.node,
+ appx = node.anchorX * node.width, appy = node.anchorY * node.height;
+
+ let { row, col, contentWidth, contentHeight } = this;
+ let { x, y } = this._local;
+ x.length = y.length = 0;
+ let leftWidth = frame.insetLeft, rightWidth = frame.insetRight, centerWidth = rect.width - leftWidth - rightWidth,
+ topHeight = frame.insetTop, bottomHeight = frame.insetBottom, centerHeight = rect.height - topHeight - bottomHeight;
+ let xScale = (node.width / (leftWidth + rightWidth)) > 1 ? 1 : (node.width / (leftWidth + rightWidth));
+ let yScale = (node.height / (topHeight + bottomHeight)) > 1 ? 1 : (node.height / (topHeight + bottomHeight));
+ let offsetWidth = 0, offsetHeight = 0;
+ if (centerWidth > 0) {
+ /*
+ * Because the float numerical calculation in javascript is not accurate enough,
+ * there is an expected result of 1.0, but the actual result is 1.000001.
+ */
+ offsetWidth = Math.floor(this.sizableWidth * 1000) / 1000 % centerWidth === 0 ? centerWidth : this.sizableWidth % centerWidth;
+ }
+ else {
+ offsetWidth = this.sizableWidth;
+ }
+ if (centerHeight > 0) {
+ offsetHeight = Math.floor(this.sizableHeight * 1000) / 1000 % centerHeight === 0 ? centerHeight : this.sizableHeight % centerHeight;
+ }
+ else {
+ offsetHeight = this.sizableHeight;
+ }
+
+ for (let i = 0; i <= col; i++) {
+ if (i === 0) {
+ x[i] = - appx;
+ }
+ else if (i > 0 && i < col) {
+ if (i === 1) {
+ x[i] = leftWidth * xScale + Math.min(centerWidth, this.sizableWidth) - appx;
+ }
+ else {
+ if (centerWidth > 0) {
+ if (i === (col - 1)) {
+ x[i] = leftWidth + offsetWidth + centerWidth * (i - 2) - appx;
+ }
+ else {
+ x[i] = leftWidth + Math.min(centerWidth, this.sizableWidth) + centerWidth * (i - 2) - appx;
+ }
+ }
+ else {
+ x[i] = leftWidth + this.sizableWidth - appx;
+ }
+ }
+ }
+ else if (i === col) {
+ x[i] = Math.min(leftWidth + this.sizableWidth + rightWidth, contentWidth) - appx;
+ }
+ }
+ for (let i = 0; i <= row; i++) {
+ if (i === 0) {
+ y[i] = - appy;
+ }
+ else if (i > 0 && i < row) {
+ if (i === 1) {
+ y[i] = bottomHeight * yScale + Math.min(centerHeight, this.sizableHeight) - appy;
+ }
+ else {
+ if (centerHeight > 0) {
+ if (i === (row - 1)) {
+ y[i] = bottomHeight + offsetHeight + (i - 2) * centerHeight - appy;
+ }
+ else {
+ y[i] = bottomHeight + Math.min(centerHeight, this.sizableHeight) + (i - 2) * centerHeight - appy;
+ }
+ }
+ else {
+ y[i] = bottomHeight + this.sizableHeight - appy;
+ }
+ }
+ }
+ else if (i === row) {
+ y[i] = Math.min(bottomHeight + this.sizableHeight + topHeight, contentHeight) - appy;
+ }
+ }
+
+ this.updateWorldVerts(sprite);
+ }
+
+ updateWorldVerts (sprite) {
+ let renderData = this._renderData;
+ let local = this._local;
+ let localX = local.x, localY = local.y;
+ let world = renderData.vDatas[0];
+ let { row, col } = this;
+ let matrix = sprite.node._worldMatrix;
+ let matrixm = matrix.m;
+ let a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
+ tx = matrixm[12], ty = matrixm[13];
+
+ let x, x1, y, y1;
+ let floatsPerVert = this.floatsPerVert;
+ let vertexOffset = 0;
+ for (let yindex = 0, ylength = row; yindex < ylength; ++yindex) {
+ y = localY[yindex];
+ y1 = localY[yindex + 1];
+ for (let xindex = 0, xlength = col; xindex < xlength; ++xindex) {
+ x = localX[xindex];
+ x1 = localX[xindex + 1];
+
+ // lb
+ world[vertexOffset] = x * a + y * c + tx;
+ world[vertexOffset + 1] = x * b + y * d + ty;
+ vertexOffset += floatsPerVert;
+ // rb
+ world[vertexOffset] = x1 * a + y * c + tx;
+ world[vertexOffset + 1] = x1 * b + y * d + ty;
+ vertexOffset += floatsPerVert;
+ // lt
+ world[vertexOffset] = x * a + y1 * c + tx;
+ world[vertexOffset + 1] = x * b + y1 * d + ty;
+ vertexOffset += floatsPerVert;
+ // rt
+ world[vertexOffset] = x1 * a + y1 * c + tx;
+ world[vertexOffset + 1] = x1 * b + y1 * d + ty;
+ vertexOffset += floatsPerVert;
+ }
+ }
+ }
+
+ updateUVs (sprite) {
+ let verts = this._renderData.vDatas[0];
+ if (!verts) return;
+
+ let frame = sprite._spriteFrame;
+ let rect = frame._rect;
+ let leftWidth = frame.insetLeft, rightWidth = frame.insetRight, centerWidth = rect.width - leftWidth - rightWidth,
+ topHeight = frame.insetTop, bottomHeight = frame.insetBottom, centerHeight = rect.height - topHeight - bottomHeight;
+
+ let { row, col, hRepeat, vRepeat } = this;
+ let coefu = 0, coefv = 0;
+ let uv = sprite.spriteFrame.uv;
+ let uvSliced = sprite.spriteFrame.uvSliced;
+ let rotated = sprite.spriteFrame._rotated;
+ let floatsPerVert = this.floatsPerVert, uvOffset = this.uvOffset;
+ for (let yindex = 0, ylength = row; yindex < ylength; ++yindex) {
+ if (this.sizableHeight > centerHeight) {
+ if (this.sizableHeight >= yindex * centerHeight) {
+ coefv = 1;
+ }
+ else {
+ coefv = vRepeat % 1;
+ }
+ }
+ else {
+ coefv = vRepeat;
+ }
+ for (let xindex = 0, xlength = col; xindex < xlength; ++xindex) {
+ if (this.sizableWidth > centerWidth) {
+ if (this.sizableWidth >= xindex * centerWidth) {
+ coefu = 1;
+ }
+ else {
+ coefu = hRepeat % 1;
+ }
+ }
+ else {
+ coefu = hRepeat;
+ }
+
+ // UV
+ if (rotated) {
+ // lb
+ verts[uvOffset] = uv[0];
+ verts[uvOffset + 1] = uv[1];
+ uvOffset += floatsPerVert;
+ // rb
+ verts[uvOffset] = uv[0];
+ verts[uvOffset + 1] = uv[1] + (uv[7] - uv[1]) * coefu;
+ uvOffset += floatsPerVert;
+ // lt
+ verts[uvOffset] = uv[0] + (uv[6] - uv[0]) * coefv;
+ verts[uvOffset + 1] = uv[1];
+ uvOffset += floatsPerVert;
+ // rt
+ verts[uvOffset] = verts[uvOffset - floatsPerVert];
+ verts[uvOffset + 1] = verts[uvOffset + 1 - floatsPerVert * 2];
+ uvOffset += floatsPerVert;
+ }
+ else {
+ // lb
+ if (xindex === 0) {
+ verts[uvOffset] = uv[0];
+ }
+ else if (xindex > 0 && xindex < (col - 1)) {
+ verts[uvOffset] = uvSliced[1].u;
+ }
+ else if(xindex === (col - 1)) {
+ verts[uvOffset] = uvSliced[2].u;
+ }
+ if (yindex === 0) {
+ verts[uvOffset + 1] = uvSliced[0].v;
+ }
+ else if (yindex > 0 && yindex < (row - 1)) {
+ verts[uvOffset + 1] = uvSliced[4].v;
+ }
+ else if (yindex === (row - 1)) {
+ verts[uvOffset + 1] = uvSliced[8].v;
+ }
+ uvOffset += floatsPerVert;
+ // rb
+ if (xindex === 0) {
+ verts[uvOffset] = uvSliced[1].u + (uvSliced[2].u - uvSliced[1].u) * coefu;
+ }
+ else if (xindex > 0 && xindex < (col - 1)) {
+ verts[uvOffset] = uvSliced[1].u + (uvSliced[2].u - uvSliced[1].u) * coefu;
+ }
+ else if (xindex === (col - 1)){
+ verts[uvOffset] = uvSliced[3].u;
+ }
+ if (yindex === 0) {
+ verts[uvOffset + 1] = uvSliced[0].v;
+ }
+ else if (yindex > 0 && yindex < (row - 1)) {
+ verts[uvOffset + 1] = uvSliced[4].v;
+ }
+ else if (yindex === (row - 1)) {
+ verts[uvOffset + 1] = uvSliced[8].v;
+ }
+ uvOffset += floatsPerVert;
+ // lt
+ if (xindex === 0) {
+ verts[uvOffset] = uv[0];
+ }
+ else if (xindex > 0 && xindex < (col - 1)) {
+ verts[uvOffset] = uvSliced[1].u;
+ }
+ else if (xindex === (col - 1)) {
+ verts[uvOffset] = uvSliced[2].u;
+ }
+ if (yindex === 0) {
+ verts[uvOffset + 1] = uvSliced[4].v + (uvSliced[8].v - uvSliced[4].v) * coefv;
+ }
+ else if (yindex > 0 && yindex < (row - 1)) {
+ verts[uvOffset + 1] = uvSliced[4].v + (uvSliced[8].v - uvSliced[4].v) * coefv;
+ }
+ else if (yindex === (row - 1)) {
+ verts[uvOffset + 1] = uvSliced[12].v;
+ }
+ uvOffset += floatsPerVert;
+ // rt
+ verts[uvOffset] = verts[uvOffset - floatsPerVert * 2];
+ verts[uvOffset + 1] = verts[uvOffset + 1 - floatsPerVert];
+ uvOffset += floatsPerVert;
+ }
+ }
+ }
+ }
+}
+
diff --git a/cocos2d/core/renderer/webgl/assemblers/sprite/3d/bar-filled.js b/cocos2d/core/renderer/webgl/assemblers/sprite/3d/bar-filled.js
new file mode 100644
index 00000000000..a741559560e
--- /dev/null
+++ b/cocos2d/core/renderer/webgl/assemblers/sprite/3d/bar-filled.js
@@ -0,0 +1,33 @@
+/****************************************************************************
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+const Assembler3D = require('../../../../assembler-3d');
+const BarFilledAssembler = require('../2d/bar-filled');
+
+export default class BarFilledAssembler3D extends BarFilledAssembler {
+
+}
+
+cc.js.mixin(BarFilledAssembler3D.prototype, Assembler3D);
diff --git a/cocos2d/core/renderer/webgl/assemblers/sprite/3d/mesh.js b/cocos2d/core/renderer/webgl/assemblers/sprite/3d/mesh.js
new file mode 100644
index 00000000000..d9f433a7f51
--- /dev/null
+++ b/cocos2d/core/renderer/webgl/assemblers/sprite/3d/mesh.js
@@ -0,0 +1,53 @@
+/****************************************************************************
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import Vec3 from '../../../../../value-types/vec3';
+const Assembler3D = require('../../../../assembler-3d');
+const MeshAssembler = require('../2d/mesh');
+
+let vec3_temp = new Vec3();
+
+export default class MeshAssembler3D extends MeshAssembler {
+
+}
+
+cc.js.mixin(MeshAssembler3D.prototype, Assembler3D, {
+ updateWorldVerts (comp) {
+ let matrix = comp.node._worldMatrix;
+ let local = this._local;
+ let world = this._renderData.vDatas[0];
+
+ let floatsPerVert = this.floatsPerVert;
+ for (let i = 0, l = local.length/2; i < l; i++) {
+ Vec3.set(vec3_temp, local[i*2], local[i*2+1], 0);
+ Vec3.transformMat4(vec3_temp, vec3_temp, matrix);
+
+ let dstOffset = floatsPerVert * i;
+ world[dstOffset] = vec3_temp.x;
+ world[dstOffset+1] = vec3_temp.y;
+ world[dstOffset+2] = vec3_temp.z;
+ }
+ }
+});
diff --git a/cocos2d/core/renderer/webgl/assemblers/sprite/3d/radial-filled.js b/cocos2d/core/renderer/webgl/assemblers/sprite/3d/radial-filled.js
new file mode 100644
index 00000000000..1fb8ff35917
--- /dev/null
+++ b/cocos2d/core/renderer/webgl/assemblers/sprite/3d/radial-filled.js
@@ -0,0 +1,53 @@
+/****************************************************************************
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import Vec3 from '../../../../../value-types/vec3';
+const Assembler3D = require('../../../../assembler-3d');
+const RadialFilledAssembler = require('../2d/radial-filled');
+
+const vec3_temp_local = new Vec3();
+const vec3_temp_world = new Vec3();
+
+export default class RadialFilledAssembler3D extends RadialFilledAssembler {
+
+}
+
+cc.js.mixin(RadialFilledAssembler3D.prototype, Assembler3D, {
+ updateWorldVerts (sprite) {
+ let matrix = sprite.node._worldMatrix;
+ let local = this._local;
+ let world = this._renderData.vDatas[0];
+
+ let floatsPerVert = this.floatsPerVert;
+ for (let offset = 0; offset < world.length; offset += floatsPerVert) {
+ Vec3.set(vec3_temp_local, local[offset], local[offset+1], 0);
+ Vec3.transformMat4(vec3_temp_world, vec3_temp_local, matrix);
+
+ world[offset] = vec3_temp_world.x;
+ world[offset+1] = vec3_temp_world.y;
+ world[offset+2] = vec3_temp_world.z;
+ }
+ }
+});
diff --git a/cocos2d/core/renderer/webgl/assemblers/sprite/3d/simple.js b/cocos2d/core/renderer/webgl/assemblers/sprite/3d/simple.js
new file mode 100644
index 00000000000..675d792decc
--- /dev/null
+++ b/cocos2d/core/renderer/webgl/assemblers/sprite/3d/simple.js
@@ -0,0 +1,33 @@
+/****************************************************************************
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+const Assembler3D = require('../../../../assembler-3d');
+const SimpleAssembler = require('../2d/simple');
+
+export default class SimpleAssembler3D extends SimpleAssembler {
+
+}
+
+cc.js.mixin(SimpleAssembler3D.prototype, Assembler3D);
diff --git a/cocos2d/core/renderer/webgl/assemblers/sprite/3d/sliced.js b/cocos2d/core/renderer/webgl/assemblers/sprite/3d/sliced.js
new file mode 100644
index 00000000000..742683e8752
--- /dev/null
+++ b/cocos2d/core/renderer/webgl/assemblers/sprite/3d/sliced.js
@@ -0,0 +1,60 @@
+/****************************************************************************
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import Vec3 from '../../../../../value-types/vec3';
+
+const Assembler3D = require('../../../../assembler-3d');
+const SlicedAssembler = require('../2d/sliced');
+
+const vec3_temp_local = new Vec3();
+const vec3_temp_world = new Vec3();
+
+export default class SlicedAssembler3D extends SlicedAssembler {
+
+}
+
+cc.js.mixin(SlicedAssembler3D.prototype, Assembler3D, {
+ updateWorldVerts (sprite) {
+ let matrix = sprite.node._worldMatrix;
+ let local = this._local;
+ let world = this._renderData.vDatas[0];
+
+ let floatsPerVert = this.floatsPerVert;
+ for (let row = 0; row < 4; ++row) {
+ let localRowY = local[row * 2 + 1];
+ for (let col = 0; col < 4; ++col) {
+ let localColX = local[col * 2];
+
+ Vec3.set(vec3_temp_local, localColX, localRowY, 0);
+ Vec3.transformMat4(vec3_temp_world, vec3_temp_local, matrix);
+
+ let worldIndex = (row * 4 + col) * floatsPerVert;
+ world[worldIndex] = vec3_temp_world.x;
+ world[worldIndex+1] = vec3_temp_world.y;
+ world[worldIndex+2] = vec3_temp_world.z;
+ }
+ }
+ }
+});
diff --git a/cocos2d/core/renderer/webgl/assemblers/sprite/3d/tiled.js b/cocos2d/core/renderer/webgl/assemblers/sprite/3d/tiled.js
new file mode 100644
index 00000000000..5e40cda1605
--- /dev/null
+++ b/cocos2d/core/renderer/webgl/assemblers/sprite/3d/tiled.js
@@ -0,0 +1,74 @@
+/****************************************************************************
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import Vec3 from '../../../../../value-types/vec3';
+
+const Assembler3D = require('../../../../assembler-3d');
+const TiledAssembler = require('../2d/tiled');
+
+let vec3_temps = [];
+for (let i = 0; i < 4; i++) {
+ vec3_temps.push(new Vec3);
+}
+
+export default class TiledAssembler3D extends TiledAssembler {
+
+}
+
+cc.js.mixin(TiledAssembler3D.prototype, Assembler3D, {
+ updateWorldVerts (sprite) {
+ let local = this._local;
+ let localX = local.x, localY = local.y;
+ let world = this._renderData.vDatas[0];
+ let { row, col } = this;
+ let matrix = sprite.node._worldMatrix;
+ let x, x1, y, y1;
+ let vertexOffset = 0;
+ for (let yindex = 0, ylength = row; yindex < ylength; ++yindex) {
+ y = localY[yindex];
+ y1 = localY[yindex + 1];
+ for (let xindex = 0, xlength = col; xindex < xlength; ++xindex) {
+ x = localX[xindex];
+ x1 = localX[xindex + 1];
+
+ Vec3.set(vec3_temps[0], x, y, 0);
+ Vec3.set(vec3_temps[1], x1, y, 0);
+ Vec3.set(vec3_temps[2], x, y1, 0);
+ Vec3.set(vec3_temps[3], x1, y1, 0);
+
+ for (let i = 0; i < 4; i++) {
+ let vec3_temp = vec3_temps[i];
+ Vec3.transformMat4(vec3_temp, vec3_temp, matrix);
+ let offset = i * 6;
+ world[vertexOffset + offset] = vec3_temp.x;
+ world[vertexOffset + offset + 1] = vec3_temp.y;
+ world[vertexOffset + offset + 2] = vec3_temp.z;
+ }
+
+ vertexOffset += 24;
+ }
+ }
+ }
+});
diff --git a/cocos2d/core/renderer/webgl/assemblers/sprite/bar-filled.js b/cocos2d/core/renderer/webgl/assemblers/sprite/bar-filled.js
deleted file mode 100644
index 474fe243802..00000000000
--- a/cocos2d/core/renderer/webgl/assemblers/sprite/bar-filled.js
+++ /dev/null
@@ -1,248 +0,0 @@
-/****************************************************************************
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-const Sprite = require('../../../../components/CCSprite');
-const FillType = Sprite.FillType;
-
-const dynamicAtlasManager = require('../../../utils/dynamic-atlas/manager');
-
-module.exports = {
- useModel: false,
- updateRenderData (sprite) {
- let frame = sprite.spriteFrame;
-
- // TODO: Material API design and export from editor could affect the material activation process
- // need to update the logic here
- if (frame) {
- if (!frame._original && dynamicAtlasManager) {
- dynamicAtlasManager.insertSpriteFrame(frame);
- }
- if (sprite._material._texture !== frame._texture) {
- sprite._activateMaterial();
- }
- }
-
- let renderData = sprite._renderData;
- if (renderData && frame) {
- let uvDirty = renderData.uvDirty,
- vertDirty = renderData.vertDirty;
-
- if (!uvDirty && !vertDirty) {
- return sprite.__allocedDatas;
- }
-
- let fillStart = sprite._fillStart;
- let fillRange = sprite._fillRange;
-
- if (fillRange < 0) {
- fillStart += fillRange;
- fillRange = -fillRange;
- }
-
- fillRange = fillStart + fillRange;
-
- fillStart = fillStart > 1.0 ? 1.0 : fillStart;
- fillStart = fillStart < 0.0 ? 0.0 : fillStart;
-
- fillRange = fillRange > 1.0 ? 1.0 : fillRange;
- fillRange = fillRange < 0.0 ? 0.0 : fillRange;
- fillRange = fillRange - fillStart;
- fillRange = fillRange < 0 ? 0 : fillRange;
-
- let fillEnd = fillStart + fillRange;
- fillEnd = fillEnd > 1 ? 1 : fillEnd;
-
- if (uvDirty) {
- this.updateUVs(sprite, fillStart, fillEnd);
- }
- if (vertDirty) {
- this.updateVerts(sprite, fillStart, fillEnd);
- this.updateWorldVerts(sprite);
- }
- }
- },
-
- updateUVs (sprite, fillStart, fillEnd) {
- let spriteFrame = sprite._spriteFrame,
- renderData = sprite._renderData,
- data = renderData._data;
-
- //build uvs
- let atlasWidth = spriteFrame._texture.width;
- let atlasHeight = spriteFrame._texture.height;
- let textureRect = spriteFrame._rect;
- //uv computation should take spritesheet into account.
- let ul, vb, ur, vt;
- let quadUV0, quadUV1, quadUV2, quadUV3, quadUV4, quadUV5, quadUV6, quadUV7;
- if (spriteFrame._rotated) {
- ul = (textureRect.x) / atlasWidth;
- vb = (textureRect.y + textureRect.width) / atlasHeight;
- ur = (textureRect.x + textureRect.height) / atlasWidth;
- vt = (textureRect.y) / atlasHeight;
-
- quadUV0 = quadUV2 = ul;
- quadUV4 = quadUV6 = ur;
- quadUV3 = quadUV7 = vb;
- quadUV1 = quadUV5 = vt;
- }
- else {
- ul = (textureRect.x) / atlasWidth;
- vb = (textureRect.y + textureRect.height) / atlasHeight;
- ur = (textureRect.x + textureRect.width) / atlasWidth;
- vt = (textureRect.y) / atlasHeight;
-
- quadUV0 = quadUV4 = ul;
- quadUV2 = quadUV6 = ur;
- quadUV1 = quadUV3 = vb;
- quadUV5 = quadUV7 = vt;
- }
-
- switch (sprite._fillType) {
- case FillType.HORIZONTAL:
- data[0].u = quadUV0 + (quadUV2 - quadUV0) * fillStart;
- data[0].v = quadUV1;
- data[1].u = quadUV0 + (quadUV2 - quadUV0) * fillEnd;
- data[1].v = quadUV3;
- data[2].u = quadUV4 + (quadUV6 - quadUV4) * fillStart;
- data[2].v = quadUV5;
- data[3].u = quadUV4 + (quadUV6 - quadUV4) * fillEnd;
- data[3].v = quadUV7;
- break;
- case FillType.VERTICAL:
- data[0].u = quadUV0;
- data[0].v = quadUV1 + (quadUV5 - quadUV1) * fillStart;
- data[1].u = quadUV2;
- data[1].v = quadUV3 + (quadUV7 - quadUV3) * fillStart;
- data[2].u = quadUV4;
- data[2].v = quadUV1 + (quadUV5 - quadUV1) * fillEnd;
- data[3].u = quadUV6;
- data[3].v = quadUV3 + (quadUV7 - quadUV3) * fillEnd;
- break;
- default:
- cc.errorID(2626);
- break;
- }
-
- renderData.uvDirty = false;
- },
-
- updateVerts (sprite, fillStart, fillEnd) {
- let renderData = sprite._renderData,
- data = renderData._data,
- node = sprite.node,
- width = node.width, height = node.height,
- appx = node.anchorX * width, appy = node.anchorY * height;
-
- let l = -appx, b = -appy,
- r = width-appx, t = height-appy;
-
- let progressStart, progressEnd;
- switch (sprite._fillType) {
- case FillType.HORIZONTAL:
- progressStart = l + (r - l) * fillStart;
- progressEnd = l + (r - l) * fillEnd;
-
- l = progressStart;
- r = progressEnd;
- break;
- case FillType.VERTICAL:
- progressStart = b + (t - b) * fillStart;
- progressEnd = b + (t - b) * fillEnd;
-
- b = progressStart;
- t = progressEnd;
- break;
- default:
- cc.errorID(2626);
- break;
- }
-
- data[4].x = l;
- data[4].y = b;
- data[5].x = r;
- data[5].y = b;
- data[6].x = l;
- data[6].y = t;
- data[7].x = r;
- data[7].y = t;
-
- renderData.vertDirty = false;
- },
-
- createData (sprite) {
- let renderData = sprite.requestRenderData();
- // 0-4 for world verts
- // 5-8 for local verts
- renderData.dataLength = 8;
- renderData.vertexCount = 4;
- renderData.indiceCount = 6;
- return renderData;
- },
-
- updateWorldVerts (sprite) {
- let node = sprite.node,
- data = sprite._renderData._data;
-
- let matrix = node._worldMatrix,
- a = matrix.m00, b = matrix.m01, c = matrix.m04, d = matrix.m05,
- tx = matrix.m12, ty = matrix.m13;
-
- for (let i = 0; i < 4; i++) {
- let local = data[i+4];
- let world = data[i];
- world.x = local.x * a + local.y * c + tx;
- world.y = local.x * b + local.y * d + ty;
- }
- },
-
- fillBuffers (sprite, renderer) {
- if (renderer.worldMatDirty) {
- this.updateWorldVerts(sprite);
- }
-
- let data = sprite._renderData._data,
- node = sprite.node,
- matrix = node._worldMatrix,
- a = matrix.m00, b = matrix.m01, c = matrix.m04, d = matrix.m05,
- tx = matrix.m12, ty = matrix.m13;
-
- let buffer = renderer._quadBuffer,
- vertexOffset = buffer.byteOffset >> 2;
-
- buffer.request(4, 6);
-
- // buffer data may be realloc, need get reference after request.
- let vbuf = buffer._vData;
-
- // vertex
- for (let i = 0; i < 4; i++) {
- let vert = data[i];
- vbuf[vertexOffset++] = vert.x;
- vbuf[vertexOffset++] = vert.y;
- vbuf[vertexOffset++] = vert.u;
- vbuf[vertexOffset++] = vert.v;
- }
- }
-};
diff --git a/cocos2d/core/renderer/webgl/assemblers/sprite/index.js b/cocos2d/core/renderer/webgl/assemblers/sprite/index.js
index c59947b09c4..8ae3efe5268 100644
--- a/cocos2d/core/renderer/webgl/assemblers/sprite/index.js
+++ b/cocos2d/core/renderer/webgl/assemblers/sprite/index.js
@@ -1,75 +1,60 @@
-/****************************************************************************
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-const Sprite = require('../../../../components/CCSprite');
-
-const SpriteType = Sprite.Type;
-const FillType = Sprite.FillType;
-
-const simpleRenderUtil = require('./simple');
-const slicedRenderUtil = require('./sliced');
-const tiledRenderUtil = require('./tiled');
-const radialFilledRenderUtil = require('./radial-filled');
-const barFilledRenderUtil = require('./bar-filled');
-const meshRenderUtil = require('./mesh');
-
-// Inline all type switch to avoid jit deoptimization during inlined function change
-
-let spriteAssembler = {
- getAssembler (sprite) {
- let util = simpleRenderUtil;
-
+import Asembler from '../../../assembler';
+import { Type, FillType } from '../../../../components/CCSprite';
+
+import Simple from "./2d/simple";
+import Sliced from "./2d/sliced";
+import Tiled from "./2d/tiled";
+import RadialFilled from "./2d/radial-filled";
+import BarFilled from "./2d/bar-filled";
+import Mesh from './2d/mesh';
+
+import Simple3D from "./3d/simple";
+import Sliced3D from "./3d/sliced";
+import Tiled3D from "./3d/tiled";
+import RadialFilled3D from "./3d/radial-filled";
+import BarFilled3D from "./3d/bar-filled";
+import Mesh3D from './3d/mesh';
+
+let ctor = {
+ getConstructor(sprite) {
+ let is3DNode = sprite.node.is3DNode;
+
+ let ctor = is3DNode ? Simple3D : Simple;
switch (sprite.type) {
- case SpriteType.SLICED:
- util = slicedRenderUtil;
+ case Type.SLICED:
+ ctor = is3DNode ? Sliced3D : Sliced;
break;
- case SpriteType.TILED:
- util = tiledRenderUtil;
+ case Type.TILED:
+ ctor = is3DNode ? Tiled3D : Tiled;
break;
- case SpriteType.FILLED:
+ case Type.FILLED:
if (sprite._fillType === FillType.RADIAL) {
- util = radialFilledRenderUtil;
- }
- else {
- util = barFilledRenderUtil;
+ ctor = is3DNode ? RadialFilled3D : RadialFilled;
+ } else {
+ ctor = is3DNode ? BarFilled3D : BarFilled;
}
break;
- case SpriteType.MESH:
- util = meshRenderUtil;
+ case Type.MESH:
+ ctor = is3DNode ? Mesh3D : Mesh;
break;
}
- return util;
+ return ctor;
},
- // Skip invalid sprites (without own _assembler)
- updateRenderData (sprite) {
- return sprite.__allocedDatas;
- }
+ Simple,
+ Sliced,
+ Tiled,
+ RadialFilled,
+ BarFilled,
+ Mesh,
+
+ Simple3D,
+ Sliced3D,
+ Tiled3D,
+ RadialFilled3D,
+ BarFilled3D,
+ Mesh3D,
};
-Sprite._assembler = spriteAssembler;
-
-module.exports = spriteAssembler;
+Asembler.register(cc.Sprite, ctor);
diff --git a/cocos2d/core/renderer/webgl/assemblers/sprite/mesh.js b/cocos2d/core/renderer/webgl/assemblers/sprite/mesh.js
deleted file mode 100644
index e8f024b84bf..00000000000
--- a/cocos2d/core/renderer/webgl/assemblers/sprite/mesh.js
+++ /dev/null
@@ -1,198 +0,0 @@
-/****************************************************************************
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-const dynamicAtlasManager = require('../../../utils/dynamic-atlas/manager');
-
- module.exports = {
- useModel: false,
-
- createData (sprite) {
- return sprite.requestRenderData();
- },
-
- updateRenderData (sprite) {
- let frame = sprite.spriteFrame;
-
- // TODO: Material API design and export from editor could affect the material activation process
- // need to update the logic here
- if (frame) {
- if (!frame._original && dynamicAtlasManager) {
- dynamicAtlasManager.insertSpriteFrame(frame);
- }
- if (sprite._material._texture !== frame._texture) {
- sprite._activateMaterial();
- }
- }
-
- let renderData = sprite._renderData;
- if (renderData && frame) {
- let vertices = frame.vertices;
- if (vertices) {
- if (renderData.vertexCount !== vertices.x.length) {
- renderData.vertexCount = vertices.x.length;
- renderData.indiceCount = vertices.triangles.length;
-
- // 1 for world vertices, 2 for local vertices
- renderData.dataLength = renderData.vertexCount * 2;
-
- renderData.uvDirty = renderData.vertDirty = true;
- }
-
- if (renderData.uvDirty) {
- this.updateUVs(sprite);
- }
- let vertDirty = renderData.vertDirty;
- if (vertDirty) {
- this.updateVerts(sprite);
- this.updateWorldVerts(sprite);
- }
- }
- }
- },
-
- updateUVs (sprite) {
- let material = sprite.getMaterial();
- let texture = material.effect.getProperty('texture');
- let texw = texture._width,
- texh = texture._height;
-
- let vertices = sprite.spriteFrame.vertices,
- u = vertices.nu,
- v = vertices.nv;
-
- let renderData = sprite._renderData;
- let data = renderData._data;
- for (let i = 0, l = u.length; i < l; i++) {
- let vertice = data[i];
- vertice.u = u[i];
- vertice.v = v[i];
- }
-
- renderData.uvDirty = false;
- },
-
- updateVerts (sprite) {
- let node = sprite.node,
- contentWidth = Math.abs(node.width),
- contentHeight = Math.abs(node.height),
- appx = node.anchorX * contentWidth,
- appy = node.anchorY * contentHeight;
-
- let frame = sprite.spriteFrame,
- vertices = frame.vertices,
- x = vertices.x,
- y = vertices.y,
- originalWidth = frame._originalSize.width,
- originalHeight = frame._originalSize.height,
- rectWidth = frame._rect.width,
- rectHeight = frame._rect.height,
- offsetX = frame._offset.x,
- offsetY = frame._offset.y,
- trimX = offsetX + (originalWidth - rectWidth) / 2,
- trimY = offsetY + (originalHeight - rectHeight) / 2;
-
- let scaleX = contentWidth / (sprite.trim ? rectWidth : originalWidth),
- scaleY = contentHeight / (sprite.trim ? rectHeight : originalHeight);
-
- let renderData = sprite._renderData;
- let data = renderData._data;
-
- if (!sprite.trim) {
- for (let i = 0, l = x.length; i < l; i++) {
- let vertice = data[i+l];
- vertice.x = (x[i]) * scaleX - appx;
- vertice.y = (originalHeight - y[i]) * scaleY - appy;
- }
- }
- else {
- for (let i = 0, l = x.length; i < l; i++) {
- let vertice = data[i+l];
- vertice.x = (x[i] - trimX) * scaleX - appx;
- vertice.y = (originalHeight - y[i] - trimY) * scaleY - appy;
- }
- }
-
- renderData.vertDirty = false;
- },
-
- updateWorldVerts (sprite) {
- let node = sprite.node,
- renderData = sprite._renderData,
- data = renderData._data;
- let matrix = node._worldMatrix;
- let a = matrix.m00, b = matrix.m01, c = matrix.m04, d = matrix.m05,
- tx = matrix.m12, ty = matrix.m13;
-
- for (let i = 0, l = renderData.vertexCount; i < l; i++) {
- let local = data[i+l];
- let world = data[i];
- world.x = local.x * a + local.y * c + tx;
- world.y = local.x * b + local.y * d + ty;
- }
- },
-
- fillBuffers (sprite, renderer) {
- let node = sprite.node,
- renderData = sprite._renderData,
- data = renderData._data;
-
- let vertices = sprite.spriteFrame.vertices;
- if (!vertices) {
- return;
- }
-
- // update world verts
- if (renderer.worldMatDirty) {
- this.updateWorldVerts(sprite);
- }
-
- // buffer
- let buffer = renderer._meshBuffer,
- vertexOffset = buffer.byteOffset >> 2;
-
- let indiceOffset = buffer.indiceOffset,
- vertexId = buffer.vertexOffset;
-
- buffer.request(renderData.vertexCount, renderData.indiceCount);
-
- // buffer data may be realloc, need get reference after request.
- let vbuf = buffer._vData,
- ibuf = buffer._iData;
-
- for (let i = 0, l = renderData.vertexCount; i < l; i++) {
- let vertice = data[i];
- vbuf[vertexOffset++] = vertice.x;
- vbuf[vertexOffset++] = vertice.y;
- vbuf[vertexOffset++] = vertice.u;
- vbuf[vertexOffset++] = vertice.v;
- }
-
- let triangles = vertices.triangles;
-
- for (let i = 0, l = triangles.length; i < l; i++) {
- ibuf[indiceOffset++] = vertexId + triangles[i];
- }
- },
-};
\ No newline at end of file
diff --git a/cocos2d/core/renderer/webgl/assemblers/sprite/radial-filled.js b/cocos2d/core/renderer/webgl/assemblers/sprite/radial-filled.js
deleted file mode 100644
index 3dca7ed1efa..00000000000
--- a/cocos2d/core/renderer/webgl/assemblers/sprite/radial-filled.js
+++ /dev/null
@@ -1,364 +0,0 @@
-/****************************************************************************
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-const dynamicAtlasManager = require('../../../utils/dynamic-atlas/manager');
-
-const PI_2 = Math.PI * 2;
-
-module.exports = {
- useModel: false,
-
- _vertPos: [cc.v2(0, 0), cc.v2(0, 0), cc.v2(0, 0), cc.v2(0, 0)],
- _vertices: [0, 0, 0, 0],
- _uvs: [0, 0, 0, 0, 0, 0, 0, 0],
- _intersectPoint_1: [cc.v2(0, 0), cc.v2(0, 0), cc.v2(0, 0), cc.v2(0, 0)],
- _intersectPoint_2: [cc.v2(0, 0), cc.v2(0, 0), cc.v2(0, 0), cc.v2(0, 0)],
- _center: cc.v2(0, 0),
- _triangles: [],
-
- createData (sprite) {
- return sprite.requestRenderData();
- },
-
- updateRenderData (sprite) {
- let frame = sprite.spriteFrame;
-
- // TODO: Material API design and export from editor could affect the material activation process
- // need to update the logic here
- if (frame) {
- if (!frame._original && dynamicAtlasManager) {
- dynamicAtlasManager.insertSpriteFrame(frame);
- }
- if (sprite._material._texture !== frame._texture) {
- sprite._activateMaterial();
- }
- }
-
- let renderData = sprite._renderData;
- if (renderData && frame) {
- if (renderData.vertDirty || renderData.uvDirty) {
- let data = renderData._data;
-
- let fillStart = sprite._fillStart;
- let fillRange = sprite._fillRange;
- if (fillRange < 0) {
- fillStart += fillRange;
- fillRange = -fillRange;
- }
-
- //do round fill start [0,1), include 0, exclude 1
- while (fillStart >= 1.0) fillStart -= 1.0;
- while (fillStart < 0.0) fillStart += 1.0;
-
- fillStart *= PI_2;
- fillRange *= PI_2;
- let fillEnd = fillStart + fillRange;
-
- //build vertices
- this._calculateVertices(sprite);
- //build uvs
- this._calculateUVs(frame);
-
- let center = this._center;
-
- let vertPos = this._vertPos,
- vertices = this._vertices;
-
- let triangles = this._triangles;
-
- this._calcInsectedPoints(vertices[0], vertices[2], vertices[1], vertices[3], center, fillStart, this._intersectPoint_1);
- this._calcInsectedPoints(vertices[0], vertices[2], vertices[1], vertices[3], center, fillStart + fillRange, this._intersectPoint_2);
-
- let offset = 0;
- for (let triangleIndex = 0; triangleIndex < 4; ++triangleIndex) {
- let triangle = triangles[triangleIndex];
- if (!triangle) {
- continue;
- }
- //all in
- if (fillRange >= PI_2) {
- renderData.dataLength = offset + 3;
- this._generateTriangle(data, offset, center, vertPos[triangle[0]], vertPos[triangle[1]]);
- offset += 3;
- continue;
- }
- //test against
- let startAngle = this._getVertAngle(center, vertPos[triangle[0]]);
- let endAngle = this._getVertAngle(center, vertPos[triangle[1]]);
- if(endAngle < startAngle) endAngle += PI_2;
- startAngle -= PI_2;
- endAngle -= PI_2;
- //testing
- for(let testIndex = 0; testIndex < 3; ++testIndex) {
- if(startAngle >= fillEnd) {
- //all out
- } else if (startAngle >= fillStart) {
- renderData.dataLength = offset + 3;
- if(endAngle >= fillEnd) {
- //startAngle to fillEnd
- this._generateTriangle(data, offset, center, vertPos[triangle[0]], this._intersectPoint_2[triangleIndex]);
- } else {
- //startAngle to endAngle
- this._generateTriangle(data, offset, center, vertPos[triangle[0]], vertPos[triangle[1]]);
- }
- offset += 3;
- } else {
- //startAngle < fillStart
- if(endAngle <= fillStart) {
- //all out
- } else if(endAngle <= fillEnd) {
- renderData.dataLength = offset + 3;
- //fillStart to endAngle
- this._generateTriangle(data, offset, center, this._intersectPoint_1[triangleIndex], vertPos[triangle[1]]);
- offset += 3;
- } else {
- renderData.dataLength = offset + 3;
- //fillStart to fillEnd
- this._generateTriangle(data, offset, center, this._intersectPoint_1[triangleIndex], this._intersectPoint_2[triangleIndex]);
- offset += 3;
- }
- }
- //add 2 * PI
- startAngle += PI_2;
- endAngle += PI_2;
- }
- }
-
- renderData.indiceCount = renderData.vertexCount = offset;
- renderData.vertDirty = renderData.uvDirty = false;
- }
- }
- },
-
- _getVertAngle: function(start, end) {
- let placementX, placementY;
- placementX = end.x - start.x;
- placementY = end.y - start.y;
-
- if(placementX === 0 && placementY === 0) {
- return undefined;
- } else if(placementX === 0) {
- if(placementY > 0) {
- return Math.PI * 0.5;
- } else {
- return Math.PI * 1.5;
- }
- } else {
- let angle = Math.atan(placementY / placementX);
- if(placementX < 0) {
- angle += Math.PI;
- }
-
- return angle;
- }
- },
-
- _generateTriangle: function(data, offset, vert0, vert1, vert2) {
- let vertices = this._vertices;
- let v0x = vertices[0];
- let v0y = vertices[1];
- let v1x = vertices[2];
- let v1y = vertices[3];
-
- data[offset].x = vert0.x;
- data[offset].y = vert0.y;
- data[offset+1].x = vert1.x;
- data[offset+1].y = vert1.y;
- data[offset+2].x = vert2.x;
- data[offset+2].y = vert2.y;
-
- let progressX, progressY;
- progressX = (vert0.x - v0x) / (v1x - v0x);
- progressY = (vert0.y - v0y) / (v1y - v0y);
- this._generateUV(progressX, progressY, data, offset);
-
- progressX = (vert1.x - v0x) / (v1x - v0x);
- progressY = (vert1.y - v0y) / (v1y - v0y);
- this._generateUV(progressX, progressY, data, offset + 1);
-
- progressX = (vert2.x - v0x) / (v1x - v0x);
- progressY = (vert2.y - v0y) / (v1y - v0y);
- this._generateUV(progressX, progressY, data, offset + 2);
- },
-
- _generateUV : function(progressX, progressY, data, offset) {
- let uvs = this._uvs;
- let px1 = uvs[0] + (uvs[2] - uvs[0]) * progressX;
- let px2 = uvs[4] + (uvs[6] - uvs[4]) * progressX;
- let py1 = uvs[1] + (uvs[3] - uvs[1]) * progressX;
- let py2 = uvs[5] + (uvs[7] - uvs[5]) * progressX;
- let uv = data[offset];
- uv.u = px1 + (px2 - px1) * progressY;
- uv.v = py1 + (py2 - py1) * progressY;
- },
-
- _calcInsectedPoints: function(left, right, bottom, top, center, angle, intersectPoints) {
- //left bottom, right, top
- let sinAngle = Math.sin(angle);
- let cosAngle = Math.cos(angle);
- let tanAngle,cotAngle;
- if(Math.cos(angle) !== 0) {
- tanAngle = sinAngle / cosAngle;
- //calculate right and left
- if((left - center.x) * cosAngle > 0) {
- let yleft = center.y + tanAngle * (left - center.x);
- intersectPoints[0].x = left;
- intersectPoints[0].y = yleft;
- }
- if((right - center.x) * cosAngle > 0) {
- let yright = center.y + tanAngle * (right - center.x);
-
- intersectPoints[2].x = right;
- intersectPoints[2].y = yright;
- }
-
- }
-
- if(Math.sin(angle) !== 0) {
- cotAngle = cosAngle / sinAngle;
- //calculate top and bottom
- if((top - center.y) * sinAngle > 0) {
- let xtop = center.x + cotAngle * (top-center.y);
- intersectPoints[3].x = xtop;
- intersectPoints[3].y = top;
- }
- if((bottom - center.y) * sinAngle > 0) {
- let xbottom = center.x + cotAngle * (bottom-center.y);
- intersectPoints[1].x = xbottom;
- intersectPoints[1].y = bottom;
- }
-
- }
- },
-
- _calculateVertices : function (sprite) {
- let node = sprite.node,
- width = node.width, height = node.height,
- appx = node.anchorX * width, appy = node.anchorY * height;
-
- let l = -appx, b = -appy,
- r = width-appx, t = height-appy;
-
- let vertices = this._vertices;
- vertices[0] = l;
- vertices[1] = b;
- vertices[2] = r;
- vertices[3] = t;
-
- let center = this._center,
- fillCenter = sprite._fillCenter,
- cx = center.x = Math.min(Math.max(0, fillCenter.x), 1) * (r-l) + l,
- cy = center.y = Math.min(Math.max(0, fillCenter.y), 1) * (t-b) + b;
-
- let vertPos = this._vertPos;
- vertPos[0].x = vertPos[3].x = l;
- vertPos[1].x = vertPos[2].x = r;
- vertPos[0].y = vertPos[1].y = b;
- vertPos[2].y = vertPos[3].y = t;
-
- let triangles = this._triangles;
- triangles.length = 0;
- if(cx !== vertices[0]) {
- triangles[0] = [3, 0];
- }
- if(cx !== vertices[2]) {
- triangles[2] = [1, 2];
- }
- if(cy !== vertices[1]) {
- triangles[1] = [0, 1];
- }
- if(cy !== vertices[3]) {
- triangles[3] = [2, 3];
- }
- },
-
- _calculateUVs : function (spriteFrame) {
- let atlasWidth = spriteFrame._texture.width;
- let atlasHeight = spriteFrame._texture.height;
- let textureRect = spriteFrame._rect;
-
- let u0, u1, v0, v1;
- let uvs = this._uvs;
-
- if (spriteFrame._rotated) {
- u0 = (textureRect.x) / atlasWidth;
- u1 = (textureRect.x + textureRect.height) / atlasWidth;
-
- v0 = (textureRect.y) / atlasHeight;
- v1 = (textureRect.y + textureRect.width) / atlasHeight;
-
- uvs[0] = uvs[2] = u0;
- uvs[4] = uvs[6] = u1;
- uvs[3] = uvs[7] = v1;
- uvs[1] = uvs[5] = v0;
- }
- else {
- u0 = (textureRect.x) / atlasWidth;
- u1 = (textureRect.x + textureRect.width) / atlasWidth;
-
- v0 = (textureRect.y) / atlasHeight;
- v1 = (textureRect.y + textureRect.height) / atlasHeight;
-
- uvs[0] = uvs[4] = u0;
- uvs[2] = uvs[6] = u1;
- uvs[1] = uvs[3] = v1;
- uvs[5] = uvs[7] = v0;
- }
- },
-
- fillBuffers (sprite, renderer) {
- let renderData = sprite._renderData,
- data = renderData._data,
- node = sprite.node;
-
- let matrix = node._worldMatrix,
- a = matrix.m00, b = matrix.m01, c = matrix.m04, d = matrix.m05,
- tx = matrix.m12, ty = matrix.m13;
-
- // buffer
- let buffer = renderer._meshBuffer,
- vertexOffset = buffer.byteOffset >> 2,
- vbuf = buffer._vData;
-
- let ibuf = buffer._iData,
- indiceOffset = buffer.indiceOffset,
- vertexId = buffer.vertexOffset;
-
- buffer.request(renderData.vertexCount, renderData.indiceCount);
-
- let count = data.length;
- for (let i = 0; i < count; i++) {
- let vert = data[i];
- vbuf[vertexOffset ++] = vert.x * a + vert.y * c + tx;
- vbuf[vertexOffset ++] = vert.x * b + vert.y * d + ty;
- vbuf[vertexOffset ++] = vert.u;
- vbuf[vertexOffset ++] = vert.v;
- }
-
- for (let i = 0; i < count; i++) {
- ibuf[indiceOffset+i] = vertexId+i;
- }
- },
-};
diff --git a/cocos2d/core/renderer/webgl/assemblers/sprite/simple.js b/cocos2d/core/renderer/webgl/assemblers/sprite/simple.js
deleted file mode 100644
index d684b2c0218..00000000000
--- a/cocos2d/core/renderer/webgl/assemblers/sprite/simple.js
+++ /dev/null
@@ -1,150 +0,0 @@
-/****************************************************************************
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-const dynamicAtlasManager = require('../../../utils/dynamic-atlas/manager');
-
-module.exports = {
- useModel: false,
-
- updateRenderData (sprite) {
- let frame = sprite._spriteFrame;
-
- // TODO: Material API design and export from editor could affect the material activation process
- // need to update the logic here
- if (frame) {
- if (!frame._original && dynamicAtlasManager) {
- dynamicAtlasManager.insertSpriteFrame(frame);
- }
- if (sprite._material._texture !== frame._texture) {
- sprite._activateMaterial();
- }
- }
-
- let renderData = sprite._renderData;
- if (renderData && frame) {
- if (renderData.vertDirty) {
- this.updateVerts(sprite);
- }
- }
- },
-
- fillBuffers (sprite, renderer) {
- let data = sprite._renderData._data,
- node = sprite.node,
- matrix = node._worldMatrix,
- a = matrix.m00, b = matrix.m01, c = matrix.m04, d = matrix.m05,
- tx = matrix.m12, ty = matrix.m13;
-
- let buffer = renderer._quadBuffer,
- vertexOffset = buffer.byteOffset >> 2;
-
- buffer.request(4, 6);
-
- // buffer data may be realloc, need get reference after request.
- let vbuf = buffer._vData;
-
- // get uv from sprite frame directly
- let uv = sprite._spriteFrame.uv;
- vbuf[vertexOffset+2] = uv[0];
- vbuf[vertexOffset+3] = uv[1];
- vbuf[vertexOffset+6] = uv[2];
- vbuf[vertexOffset+7] = uv[3];
- vbuf[vertexOffset+10] = uv[4];
- vbuf[vertexOffset+11] = uv[5];
- vbuf[vertexOffset+14] = uv[6];
- vbuf[vertexOffset+15] = uv[7];
-
- let data0 = data[0], data3 = data[3],
- vl = data0.x, vr = data3.x,
- vb = data0.y, vt = data3.y;
-
- let al = a * vl, ar = a * vr,
- bl = b * vl, br = b * vr,
- cb = c * vb, ct = c * vt,
- db = d * vb, dt = d * vt;
-
- // left bottom
- vbuf[vertexOffset] = al + cb + tx;
- vbuf[vertexOffset+1] = bl + db + ty;
- // right bottom
- vbuf[vertexOffset+4] = ar + cb + tx;
- vbuf[vertexOffset+5] = br + db + ty;
- // left top
- vbuf[vertexOffset+8] = al + ct + tx;
- vbuf[vertexOffset+9] = bl + dt + ty;
- // right top
- vbuf[vertexOffset+12] = ar + ct + tx;
- vbuf[vertexOffset+13] = br + dt + ty;
- },
-
- createData (sprite) {
- let renderData = sprite.requestRenderData();
- renderData.dataLength = 4;
- renderData.vertexCount = 4;
- renderData.indiceCount = 6;
- return renderData;
- },
-
- updateVerts (sprite) {
- let renderData = sprite._renderData,
- node = sprite.node,
- data = renderData._data,
- cw = node.width, ch = node.height,
- appx = node.anchorX * cw, appy = node.anchorY * ch,
- l, b, r, t;
- if (sprite.trim) {
- l = -appx;
- b = -appy;
- r = cw - appx;
- t = ch - appy;
- }
- else {
- let frame = sprite.spriteFrame,
- ow = frame._originalSize.width, oh = frame._originalSize.height,
- rw = frame._rect.width, rh = frame._rect.height,
- offset = frame._offset,
- scaleX = cw / ow, scaleY = ch / oh;
- let trimLeft = offset.x + (ow - rw) / 2;
- let trimRight = offset.x - (ow - rw) / 2;
- let trimBottom = offset.y + (oh - rh) / 2;
- let trimTop = offset.y - (oh - rh) / 2;
- l = trimLeft * scaleX - appx;
- b = trimBottom * scaleY - appy;
- r = cw + trimRight * scaleX - appx;
- t = ch + trimTop * scaleY - appy;
- }
-
- data[0].x = l;
- data[0].y = b;
- // data[1].x = r;
- // data[1].y = b;
- // data[2].x = l;
- // data[2].y = t;
- data[3].x = r;
- data[3].y = t;
-
- renderData.vertDirty = false;
- }
-};
diff --git a/cocos2d/core/renderer/webgl/assemblers/sprite/sliced.js b/cocos2d/core/renderer/webgl/assemblers/sprite/sliced.js
deleted file mode 100644
index 3279497dabd..00000000000
--- a/cocos2d/core/renderer/webgl/assemblers/sprite/sliced.js
+++ /dev/null
@@ -1,164 +0,0 @@
-/****************************************************************************
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-const dynamicAtlasManager = require('../../../utils/dynamic-atlas/manager');
-
-module.exports = {
- useModel: false,
-
- createData (sprite) {
- let renderData = sprite.requestRenderData();
- // 0-4 for local verts
- // 5-20 for world verts
- renderData.dataLength = 20;
-
- renderData.vertexCount = 16;
- renderData.indiceCount = 54;
- return renderData;
- },
-
- updateRenderData (sprite, batchData) {
- let frame = sprite.spriteFrame;
-
- // TODO: Material API design and export from editor could affect the material activation process
- // need to update the logic here
- if (frame) {
- if (!frame._original && dynamicAtlasManager) {
- dynamicAtlasManager.insertSpriteFrame(frame);
- }
- if (sprite._material._texture !== frame._texture) {
- sprite._activateMaterial();
- }
- }
-
- let renderData = sprite._renderData;
- if (renderData && frame) {
- let vertDirty = renderData.vertDirty;
- if (vertDirty) {
- this.updateVerts(sprite);
- this.updateWorldVerts(sprite);
- }
- }
- },
-
- updateVerts (sprite) {
- let renderData = sprite._renderData,
- data = renderData._data,
- node = sprite.node,
- width = node.width, height = node.height,
- appx = node.anchorX * width, appy = node.anchorY * height;
-
- let frame = sprite.spriteFrame;
- let leftWidth = frame.insetLeft;
- let rightWidth = frame.insetRight;
- let topHeight = frame.insetTop;
- let bottomHeight = frame.insetBottom;
-
- let sizableWidth = width - leftWidth - rightWidth;
- let sizableHeight = height - topHeight - bottomHeight;
- let xScale = width / (leftWidth + rightWidth);
- let yScale = height / (topHeight + bottomHeight);
- xScale = (isNaN(xScale) || xScale > 1) ? 1 : xScale;
- yScale = (isNaN(yScale) || yScale > 1) ? 1 : yScale;
- sizableWidth = sizableWidth < 0 ? 0 : sizableWidth;
- sizableHeight = sizableHeight < 0 ? 0 : sizableHeight;
-
- data[0].x = -appx;
- data[0].y = -appy;
- data[1].x = leftWidth * xScale - appx;
- data[1].y = bottomHeight * yScale - appy;
- data[2].x = data[1].x + sizableWidth;
- data[2].y = data[1].y + sizableHeight;
- data[3].x = width - appx;
- data[3].y = height - appy;
-
- renderData.vertDirty = false;
- },
-
- fillBuffers (sprite, renderer) {
- if (renderer.worldMatDirty) {
- this.updateWorldVerts(sprite);
- }
-
- let renderData = sprite._renderData,
- data = renderData._data;
-
- let buffer = renderer._meshBuffer,
- vertexOffset = buffer.byteOffset >> 2,
- vertexCount = renderData.vertexCount;
-
- let indiceOffset = buffer.indiceOffset,
- vertexId = buffer.vertexOffset;
-
- let uvSliced = sprite.spriteFrame.uvSliced;
-
- buffer.request(vertexCount, renderData.indiceCount);
-
- // buffer data may be realloc, need get reference after request.
- let vbuf = buffer._vData,
- ibuf = buffer._iData;
-
- for (let i = 4; i < 20; ++i) {
- let vert = data[i];
- let uvs = uvSliced[i - 4];
-
- vbuf[vertexOffset++] = vert.x;
- vbuf[vertexOffset++] = vert.y;
- vbuf[vertexOffset++] = uvs.u;
- vbuf[vertexOffset++] = uvs.v;
- }
-
- for (let r = 0; r < 3; ++r) {
- for (let c = 0; c < 3; ++c) {
- let start = vertexId + r*4 + c;
- ibuf[indiceOffset++] = start;
- ibuf[indiceOffset++] = start + 1;
- ibuf[indiceOffset++] = start + 4;
- ibuf[indiceOffset++] = start + 1;
- ibuf[indiceOffset++] = start + 5;
- ibuf[indiceOffset++] = start + 4;
- }
- }
- },
-
- updateWorldVerts (sprite) {
- let node = sprite.node,
- data = sprite._renderData._data;
-
- let matrix = node._worldMatrix,
- a = matrix.m00, b = matrix.m01, c = matrix.m04, d = matrix.m05,
- tx = matrix.m12, ty = matrix.m13;
-
- for (let row = 0; row < 4; ++row) {
- let rowD = data[row];
- for (let col = 0; col < 4; ++col) {
- let colD = data[col];
- let world = data[4 + row*4 + col];
- world.x = colD.x*a + rowD.y*c + tx;
- world.y = colD.x*b + rowD.y*d + ty;
- }
- }
- },
-};
diff --git a/cocos2d/core/renderer/webgl/assemblers/sprite/tiled.js b/cocos2d/core/renderer/webgl/assemblers/sprite/tiled.js
deleted file mode 100644
index 9e60ca17d47..00000000000
--- a/cocos2d/core/renderer/webgl/assemblers/sprite/tiled.js
+++ /dev/null
@@ -1,190 +0,0 @@
-/****************************************************************************
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-const dynamicAtlasManager = require('../../../utils/dynamic-atlas/manager');
-
-module.exports = {
- useModel: false,
-
- createData (sprite) {
- return sprite.requestRenderData();
- },
-
- updateRenderData (sprite) {
- let frame = sprite.spriteFrame;
-
- // TODO: Material API design and export from editor could affect the material activation process
- // need to update the logic here
- if (frame) {
- if (!frame._original && dynamicAtlasManager) {
- dynamicAtlasManager.insertSpriteFrame(frame);
- }
- if (sprite._material._texture !== frame._texture) {
- sprite._activateMaterial();
- }
- }
-
- let renderData = sprite._renderData;
- if (!frame || !renderData ||
- !(renderData.uvDirty || renderData.vertDirty))
- return;
-
- let texture = frame._texture;
- let texw = texture.width,
- texh = texture.height,
- rect = frame._rect;
-
- let node = sprite.node,
- contentWidth = Math.abs(node.width),
- contentHeight = Math.abs(node.height),
- appx = node.anchorX * contentWidth,
- appy = node.anchorY * contentHeight;
-
- let rectWidth = rect.width,
- rectHeight = rect.height,
- hRepeat = contentWidth / rectWidth,
- vRepeat = contentHeight / rectHeight,
- row = Math.ceil(vRepeat),
- col = Math.ceil(hRepeat);
-
- let data = renderData._data;
- renderData.dataLength = Math.max(8, row+1, col+1);
-
- for (let i = 0; i <= col; ++i) {
- data[i].x = Math.min(rectWidth * i, contentWidth) - appx;
- }
- for (let i = 0; i <= row; ++i) {
- data[i].y = Math.min(rectHeight * i, contentHeight) - appy;
- }
-
- // update data property
- renderData.vertexCount = row * col * 4;
- renderData.indiceCount = row * col * 6;
- renderData.uvDirty = false;
- renderData.vertDirty = false;
- },
-
- fillBuffers (sprite, renderer) {
- let node = sprite.node,
- renderData = sprite._renderData,
- data = renderData._data;
-
- // buffer
- let buffer = renderer._meshBuffer,
- vertexOffset = buffer.byteOffset >> 2;
-
- let indiceOffset = buffer.indiceOffset,
- vertexId = buffer.vertexOffset;
-
- buffer.request(renderData.vertexCount, renderData.indiceCount);
-
- // buffer data may be realloc, need get reference after request.
- let vbuf = buffer._vData,
- ibuf = buffer._iData;
-
- let rotated = sprite.spriteFrame._rotated;
- let uv = sprite.spriteFrame.uv;
- let rect = sprite.spriteFrame._rect;
- let contentWidth = Math.abs(node.width);
- let contentHeight = Math.abs(node.height);
- let hRepeat = contentWidth / rect.width;
- let vRepeat = contentHeight / rect.height;
- let row = Math.ceil(vRepeat),
- col = Math.ceil(hRepeat);
-
- let matrix = node._worldMatrix;
- let a = matrix.m00, b = matrix.m01, c = matrix.m04, d = matrix.m05,
- tx = matrix.m12, ty = matrix.m13;
-
- let x, x1, y, y1, coefu, coefv;
- for (let yindex = 0, ylength = row; yindex < ylength; ++yindex) {
- y = data[yindex].y;
- y1 = data[yindex+1].y;
- coefv = Math.min(1, vRepeat - yindex);
- for (let xindex = 0, xlength = col; xindex < xlength; ++xindex) {
- coefu = Math.min(1, hRepeat - xindex);
- x = data[xindex].x;
- x1 = data[xindex+1].x;
-
- // Vertex
- // lb
- vbuf[vertexOffset] = x * a + y * c + tx;
- vbuf[vertexOffset+1] = x * b + y * d + ty;
- // rb
- vbuf[vertexOffset+4] = x1 * a + y * c + tx;
- vbuf[vertexOffset+5] = x1 * b + y * d + ty;
- // lt
- vbuf[vertexOffset+8] = x * a + y1 * c + tx;
- vbuf[vertexOffset+9] = x * b + y1 * d + ty;
- // rt
- vbuf[vertexOffset+12] = x1 * a + y1 * c + tx;
- vbuf[vertexOffset+13] = x1 * b + y1 * d + ty;
-
- // UV
- if (rotated) {
- // lb
- vbuf[vertexOffset+2] = uv[0];
- vbuf[vertexOffset+3] = uv[1];
- // rb
- vbuf[vertexOffset+6] = uv[0];
- vbuf[vertexOffset+7] = uv[1] + (uv[7] - uv[1]) * coefu;
- // lt
- vbuf[vertexOffset+10] = uv[0] + (uv[6] - uv[0]) * coefv;
- vbuf[vertexOffset+11] = uv[1];
- // rt
- vbuf[vertexOffset+14] = vbuf[vertexOffset+10];
- vbuf[vertexOffset+15] = vbuf[vertexOffset+7];
- }
- else {
- // lb
- vbuf[vertexOffset+2] = uv[0];
- vbuf[vertexOffset+3] = uv[1];
- // rb
- vbuf[vertexOffset+6] = uv[0] + (uv[6] - uv[0]) * coefu;
- vbuf[vertexOffset+7] = uv[1];
- // lt
- vbuf[vertexOffset+10] = uv[0];
- vbuf[vertexOffset+11] = uv[1] + (uv[7] - uv[1]) * coefv;
- // rt
- vbuf[vertexOffset+14] = vbuf[vertexOffset+6];
- vbuf[vertexOffset+15] = vbuf[vertexOffset+11];
- }
- vertexOffset += 16;
- }
- }
-
- // update indices
- let length = renderData.indiceCount;
- for (let i = 0; i < length; i+=6) {
- ibuf[indiceOffset++] = vertexId;
- ibuf[indiceOffset++] = vertexId+1;
- ibuf[indiceOffset++] = vertexId+2;
- ibuf[indiceOffset++] = vertexId+1;
- ibuf[indiceOffset++] = vertexId+3;
- ibuf[indiceOffset++] = vertexId+2;
- vertexId += 4;
- }
- },
-};
\ No newline at end of file
diff --git a/cocos2d/core/renderer/webgl/flex-buffer.js b/cocos2d/core/renderer/webgl/flex-buffer.js
new file mode 100644
index 00000000000..0585f308551
--- /dev/null
+++ b/cocos2d/core/renderer/webgl/flex-buffer.js
@@ -0,0 +1,101 @@
+/****************************************************************************
+ LICENSING AGREEMENT
+
+ Xiamen Yaji Software Co., Ltd., (the “Licensor”) grants the user (the “Licensee”) non-exclusive and non-transferable rights to use the software according to the following conditions:
+ a. The Licensee shall pay royalties to the Licensor, and the amount of those royalties and the payment method are subject to separate negotiations between the parties.
+ b. The software is licensed for use rather than sold, and the Licensor reserves all rights over the software that are not expressly granted (whether by implication, reservation or prohibition).
+ c. The open source codes contained in the software are subject to the MIT Open Source Licensing Agreement (see the attached for the details);
+ d. The Licensee acknowledges and consents to the possibility that errors may occur during the operation of the software for one or more technical reasons, and the Licensee shall take precautions and prepare remedies for such events. In such circumstance, the Licensor shall provide software patches or updates according to the agreement between the two parties. The Licensor will not assume any liability beyond the explicit wording of this Licensing Agreement.
+ e. Where the Licensor must assume liability for the software according to relevant laws, the Licensor’s entire liability is limited to the annual royalty payable by the Licensee.
+ f. The Licensor owns the portions listed in the root directory and subdirectory (if any) in the software and enjoys the intellectual property rights over those portions. As for the portions owned by the Licensor, the Licensee shall not:
+ - i. Bypass or avoid any relevant technical protection measures in the products or services;
+ - ii. Release the source codes to any other parties;
+ - iii. Disassemble, decompile, decipher, attack, emulate, exploit or reverse-engineer these portion of code;
+ - iv. Apply it to any third-party products or services without Licensor’s permission;
+ - v. Publish, copy, rent, lease, sell, export, import, distribute or lend any products containing these portions of code;
+ - vi. Allow others to use any services relevant to the technology of these codes;
+ - vii. Conduct any other act beyond the scope of this Licensing Agreement.
+ g. This Licensing Agreement terminates immediately if the Licensee breaches this Agreement. The Licensor may claim compensation from the Licensee where the Licensee’s breach causes any damage to the Licensor.
+ h. The laws of the People's Republic of China apply to this Licensing Agreement.
+ i. This Agreement is made in both Chinese and English, and the Chinese version shall prevail the event of conflict.
+ ****************************************************************************/
+
+export default class FlexBuffer {
+ constructor (handler, index, verticesCount, indicesCount, vfmt) {
+ this._handler = handler;
+ this._index = index;
+ this._vfmt = vfmt;
+ this._verticesBytes = vfmt._bytes;
+
+ this._initVerticesCount = verticesCount;
+ this._initIndicesCount = indicesCount;
+
+ this.reset();
+ }
+
+ _reallocVData (floatsCount, oldData) {
+ this.vData = new Float32Array(floatsCount);
+ this.uintVData = new Uint32Array(this.vData.buffer);
+
+ if (oldData) {
+ this.vData.set(oldData);
+ }
+
+ this._handler.updateMesh(this._index, this.vData, this.iData);
+ }
+
+ _reallocIData (indicesCount, oldData) {
+ this.iData = new Uint16Array(indicesCount);
+
+ if (oldData) {
+ this.iData.set(oldData);
+ }
+
+ this._handler.updateMesh(this._index, this.vData, this.iData);
+ }
+
+ reserve (verticesCount, indicesCount) {
+ let floatsCount = verticesCount * this._verticesBytes >> 2;
+ let newFloatsCount = this.vData.length;
+ let realloced = false;
+
+ if (floatsCount > newFloatsCount) {
+ while (newFloatsCount < floatsCount) {
+ newFloatsCount *= 2;
+ }
+ this._reallocVData(newFloatsCount, this.vData);
+ realloced = true;
+ }
+
+ let newIndicesCount = this.iData.length;
+ if (indicesCount > newIndicesCount) {
+ while (newIndicesCount < indicesCount) {
+ newIndicesCount *= 2;
+ }
+ this._reallocIData(indicesCount, this.iData);
+ realloced = true;
+ }
+
+ return realloced;
+ }
+
+ used (verticesCount, indicesCount) {
+ this.usedVertices = verticesCount;
+ this.usedIndices = indicesCount;
+ this.usedVerticesFloats = verticesCount * this._verticesBytes >> 2;
+
+ this._handler.updateMeshRange(verticesCount, indicesCount);
+ }
+
+ reset () {
+ let floatsCount = this._initVerticesCount * this._verticesBytes >> 2;
+ this._reallocVData(floatsCount);
+ this._reallocIData(this._initIndicesCount);
+
+ this.usedVertices = 0;
+ this.usedVerticesFloats = 0;
+ this.usedIndices = 0;
+ }
+}
+
+cc.FlexBuffer = FlexBuffer
diff --git a/cocos2d/core/renderer/webgl/mesh-buffer.js b/cocos2d/core/renderer/webgl/mesh-buffer.js
index 4449c711626..47e638e669b 100644
--- a/cocos2d/core/renderer/webgl/mesh-buffer.js
+++ b/cocos2d/core/renderer/webgl/mesh-buffer.js
@@ -1,44 +1,84 @@
-const renderEngine = require('../render-engine');
-const gfx = renderEngine.gfx;
+/****************************************************************************
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import gfx from '../../../renderer/gfx';
+
+const isIOS14Device = cc.sys.os === cc.sys.OS_IOS && cc.sys.isBrowser && cc.sys.isMobile && /iPhone OS 14/.test(window.navigator.userAgent);
let MeshBuffer = cc.Class({
name: 'cc.MeshBuffer',
- ctor (renderer, vertexFormat) {
- this.byteStart = 0;
+ ctor (batcher, vertexFormat) {
+ this.init (batcher, vertexFormat);
+ },
+
+ init (batcher, vertexFormat) {
this.byteOffset = 0;
- this.indiceStart = 0;
this.indiceOffset = 0;
- this.vertexStart = 0;
this.vertexOffset = 0;
+ this.indiceStart = 0;
+
+ this._dirty = false;
this._vertexFormat = vertexFormat;
this._vertexBytes = this._vertexFormat._bytes;
+ this._arrOffset = 0;
+ this._vbArr = [];
this._vb = new gfx.VertexBuffer(
- renderer._device,
+ batcher._device,
vertexFormat,
gfx.USAGE_DYNAMIC,
new ArrayBuffer(),
0
);
+ this._vbArr[0] = this._vb;
+ this._ibArr = [];
this._ib = new gfx.IndexBuffer(
- renderer._device,
+ batcher._device,
gfx.INDEX_FMT_UINT16,
gfx.USAGE_STATIC,
new ArrayBuffer(),
0
);
+ this._ibArr[0] = this._ib;
this._vData = null;
- this._iData = null;
this._uintVData = null;
+ this._iData = null;
- this._renderer = renderer;
+ this._batcher = batcher;
- this._initVDataCount = 256 * vertexFormat._bytes; // actually 256 * 4 * (vertexFormat._bytes / 4)
+ this._initVDataCount = 256 * vertexFormat._bytes;// actually 256 * 4 * (vertexFormat._bytes / 4)
this._initIDataCount = 256 * 6;
+ this._offsetInfo = {
+ byteOffset : 0,
+ vertexOffset : 0,
+ indiceOffset : 0
+ }
this._reallocBuffer();
},
@@ -60,7 +100,51 @@ let MeshBuffer = cc.Class({
this._dirty = false;
},
+ switchBuffer () {
+ let offset = ++this._arrOffset;
+
+ this.byteOffset = 0;
+ this.vertexOffset = 0;
+ this.indiceOffset = 0;
+ this.indiceStart = 0;
+
+ if (offset < this._vbArr.length) {
+ this._vb = this._vbArr[offset];
+ this._ib = this._ibArr[offset];
+ } else {
+
+ this._vb = new gfx.VertexBuffer(
+ this._batcher._device,
+ this._vertexFormat,
+ gfx.USAGE_DYNAMIC,
+ new ArrayBuffer(),
+ 0
+ );
+ this._vbArr[offset] = this._vb;
+
+ this._ib = new gfx.IndexBuffer(
+ this._batcher._device,
+ gfx.INDEX_FMT_UINT16,
+ gfx.USAGE_STATIC,
+ new ArrayBuffer(),
+ 0
+ );
+ this._ibArr[offset] = this._ib;
+ }
+ },
+
+ checkAndSwitchBuffer (vertexCount) {
+ if (this.vertexOffset + vertexCount > 65535) {
+ this.uploadData();
+ this._batcher._flush();
+ this.switchBuffer();
+ }
+ },
+
requestStatic (vertexCount, indiceCount) {
+
+ this.checkAndSwitchBuffer(vertexCount);
+
let byteOffset = this.byteOffset + vertexCount * this._vertexBytes;
let indiceOffset = this.indiceOffset + indiceCount;
@@ -77,22 +161,31 @@ let MeshBuffer = cc.Class({
this._reallocBuffer();
}
+ this._updateOffset(vertexCount, indiceCount, byteOffset);
+ },
+ _updateOffset (vertexCount, indiceCount, byteOffset) {
+ let offsetInfo = this._offsetInfo;
+ offsetInfo.vertexOffset = this.vertexOffset;
this.vertexOffset += vertexCount;
+
+ offsetInfo.indiceOffset = this.indiceOffset;
this.indiceOffset += indiceCount;
-
+
+ offsetInfo.byteOffset = this.byteOffset;
this.byteOffset = byteOffset;
this._dirty = true;
},
request (vertexCount, indiceCount) {
- if (this._renderer._buffer !== this) {
- this._renderer._flush();
- this._renderer._buffer = this;
+ if (this._batcher._buffer !== this) {
+ this._batcher._flush();
+ this._batcher._buffer = this;
}
this.requestStatic(vertexCount, indiceCount);
+ return this._offsetInfo;
},
_reallocBuffer () {
@@ -101,19 +194,21 @@ let MeshBuffer = cc.Class({
},
_reallocVData (copyOldData) {
- let oldVData = this._vData;
+ let oldVData;
+ if (this._vData) {
+ oldVData = new Uint8Array(this._vData.buffer);
+ }
this._vData = new Float32Array(this._initVDataCount);
this._uintVData = new Uint32Array(this._vData.buffer);
+ let newData = new Uint8Array(this._uintVData.buffer);
+
if (oldVData && copyOldData) {
- let vData = this._vData;
for (let i = 0, l = oldVData.length; i < l; i++) {
- vData[i] = oldVData[i];
+ newData[i] = oldVData[i];
}
}
-
- this._vb._bytes = this._vData.byteLength;
},
_reallocIData (copyOldData) {
@@ -127,24 +222,57 @@ let MeshBuffer = cc.Class({
iData[i] = oldIData[i];
}
}
-
- this._ib._bytes = this._iData.byteLength;
},
reset () {
- this.byteStart = 0;
+ this._arrOffset = 0;
+ this._vb = this._vbArr[0];
+ this._ib = this._ibArr[0];
+
this.byteOffset = 0;
- this.indiceStart = 0;
this.indiceOffset = 0;
- this.vertexStart = 0;
this.vertexOffset = 0;
+ this.indiceStart = 0;
+
this._dirty = false;
},
destroy () {
- this._ib.destroy();
- this._vb.destroy();
+ this.reset();
+ for (let i = 0; i < this._vbArr.length; i++) {
+ let vb = this._vbArr[i];
+ vb.destroy();
+ }
+ this._vbArr = null;
+
+ for (let i = 0; i < this._ibArr.length; i++) {
+ let ib = this._ibArr[i];
+ ib.destroy();
+ }
+ this._ibArr = null;
+
+ this._ib = null;
+ this._vb = null;
+ },
+
+ forwardIndiceStartToOffset () {
+ this.indiceStart = this.indiceOffset;
}
});
+// Should not share vb and id between multiple drawcalls on iOS14, it will cost a lot of time.
+// TODO: maybe remove it after iOS14 fix it?
+if (isIOS14Device) {
+ MeshBuffer.prototype.checkAndSwitchBuffer = function (vertexCount) {
+ if (this.vertexOffset + vertexCount > 65535) {
+ this.uploadData();
+ this._batcher._flush();
+ }
+ };
+ MeshBuffer.prototype.forwardIndiceStartToOffset = function () {
+ this.uploadData();
+ this.switchBuffer();
+ }
+}
+
cc.MeshBuffer = module.exports = MeshBuffer;
diff --git a/cocos2d/core/renderer/webgl/render-component-walker.js b/cocos2d/core/renderer/webgl/model-batcher.js
similarity index 56%
rename from cocos2d/core/renderer/webgl/render-component-walker.js
rename to cocos2d/core/renderer/webgl/model-batcher.js
index 539c2fe2dbe..7655b15cd28 100644
--- a/cocos2d/core/renderer/webgl/render-component-walker.js
+++ b/cocos2d/core/renderer/webgl/model-batcher.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -23,37 +23,27 @@
THE SOFTWARE.
****************************************************************************/
-const macro = require('../../platform/CCMacro');
-const renderEngine = require('../render-engine');
-const defaultVertexFormat = require('./vertex-format').vfmtPosUv;
-const StencilManager = require('./stencil-manager');
-const dynamicAtlasManager = require('../utils/dynamic-atlas/manager');
-const RenderFlow = require('../render-flow');
+const { vfmtPosUvColor, vfmt3D } = require('./vertex-format');
const QuadBuffer = require('./quad-buffer');
const MeshBuffer = require('./mesh-buffer');
+const SpineBuffer = require('./spine-buffer');
+const Material = require('../../assets/material/CCMaterial');
let idGenerater = new (require('../../platform/id-generater'))('VertextFormat');
-const gfx = renderEngine.gfx;
-const RecyclePool = renderEngine.RecyclePool;
-const InputAssembler = renderEngine.InputAssembler;
-
-const FLOATS_PER_VERT = defaultVertexFormat._bytes / 4;
-const BYTE_PER_INDEX = 2;
-const MAX_VERTEX = macro.BATCH_VERTEX_COUNT;
-const MAX_VERTEX_BYTES = MAX_VERTEX * defaultVertexFormat._bytes;
-const MAX_INDICE = MAX_VERTEX * BYTE_PER_INDEX;
-const MAX_INDICE_BYTES = MAX_INDICE * 2;
+import InputAssembler from '../../../renderer/core/input-assembler';
+import RecyclePool from '../../../renderer/memop/recycle-pool';
+import Model from '../../../renderer/scene/model';
let _buffers = {};
-const empty_material = new renderEngine.Material();
-empty_material.updateHash();
+const empty_material = new Material();
+const empty_ia = new InputAssembler();
+empty_ia._count = 0;
-var RenderComponentWalker = function (device, renderScene) {
+var ModelBatcher = function (device, renderScene) {
this._renderScene = renderScene;
this._device = device;
- this._stencilMgr = StencilManager.sharedManager;
this.walking = false;
this.material = empty_material;
@@ -64,13 +54,15 @@ var RenderComponentWalker = function (device, renderScene) {
}, 16);
this._modelPool = new RecyclePool(function () {
- return new renderEngine.Model();
+ return new Model();
}, 16);
// buffers
- this._quadBuffer = this.getBuffer('quad', defaultVertexFormat);
- this._meshBuffer = this.getBuffer('mesh', defaultVertexFormat);
- this._buffer = this._quadBuffer;
+ this._quadBuffer = this.getBuffer('quad', vfmtPosUvColor);
+ this._meshBuffer = this.getBuffer('mesh', vfmtPosUvColor);
+ this._quadBuffer3D = this.getBuffer('quad', vfmt3D);
+ this._meshBuffer3D = this.getBuffer('mesh', vfmt3D);
+ this._buffer = this._meshBuffer;
this._batchedModels = [];
this._dummyNode = new cc.Node();
@@ -81,12 +73,10 @@ var RenderComponentWalker = function (device, renderScene) {
this.parentOpacity = 1;
this.parentOpacityDirty = 0;
this.worldMatDirty = 0;
-
- RenderFlow.init(this);
};
-RenderComponentWalker.prototype = {
- constructor: RenderComponentWalker,
+ModelBatcher.prototype = {
+ constructor: ModelBatcher,
reset() {
// Reset pools
@@ -97,8 +87,10 @@ RenderComponentWalker.prototype = {
let models = this._batchedModels;
for (let i = 0; i < models.length; ++i) {
// remove from scene
- models[i].clearInputAssemblers();
- models[i].clearEffects();
+ // models[i].clearInputAssemblers();
+ // models[i].clearEffects();
+ models[i].setInputAssembler(null);
+ models[i].setEffect(null);
scene.removeModel(models[i]);
}
this._modelPool.reset();
@@ -108,7 +100,7 @@ RenderComponentWalker.prototype = {
for (let key in _buffers) {
_buffers[key].reset();
}
- this._buffer = this._quadBuffer;
+ this._buffer = this._meshBuffer;
// reset caches for handle render components
this.node = this._dummyNode;
@@ -118,119 +110,97 @@ RenderComponentWalker.prototype = {
this.parentOpacity = 1;
this.parentOpacityDirty = 0;
this.worldMatDirty = 0;
+ },
- // reset stencil manager's cache
- this._stencilMgr.reset();
+ _flushMaterial (material) {
+ if (!material) {
+ return;
+ }
+ this.material = material;
+ let effect = material.effect;
+ if (!effect) return;
+
+ // Generate model
+ let model = this._modelPool.add();
+ this._batchedModels.push(model);
+ model.sortKey = this._sortKey++;
+ model._cullingMask = this.cullingMask;
+ model.setNode(this.node);
+ model.setEffect(effect, null);
+ model.setInputAssembler(empty_ia);
+
+ this._renderScene.addModel(model);
},
_flush () {
let material = this.material,
buffer = this._buffer,
- indiceStart = buffer.indiceStart,
- indiceOffset = buffer.indiceOffset,
- indiceCount = indiceOffset - indiceStart;
+ indiceCount = buffer.indiceOffset - buffer.indiceStart;
if (!this.walking || !material || indiceCount <= 0) {
return;
}
let effect = material.effect;
-
+ if (!effect) return;
+
// Generate ia
let ia = this._iaPool.add();
ia._vertexBuffer = buffer._vb;
ia._indexBuffer = buffer._ib;
- ia._start = indiceStart;
+ ia._start = buffer.indiceStart;
ia._count = indiceCount;
-
- // Check stencil state and modify pass
- this._stencilMgr.handleEffect(effect);
// Generate model
let model = this._modelPool.add();
this._batchedModels.push(model);
model.sortKey = this._sortKey++;
- model._cullingMask = CC_EDITOR ? 1 : this.cullingMask;
+ model._cullingMask = this.cullingMask;
model.setNode(this.node);
- model.addEffect(effect);
- model.addInputAssembler(ia);
+ model.setEffect(effect);
+ model.setInputAssembler(ia);
this._renderScene.addModel(model);
-
- buffer.byteStart = buffer.byteOffset;
- buffer.indiceStart = buffer.indiceOffset;
- buffer.vertexStart = buffer.vertexOffset;
+ buffer.forwardIndiceStartToOffset();
},
- _flushIA (iaRenderData) {
- let material = iaRenderData.material;
-
- if (!iaRenderData.ia || !material) {
+ _flushIA (ia) {
+ if (!ia) {
return;
}
- this.material = material;
-
- // Check stencil state and modify pass
- let effect = this._stencilMgr.handleEffect(material.effect);
+ let material = this.material;
+ let effect = material.effect;
+ if (!effect) return;
// Generate model
let model = this._modelPool.add();
this._batchedModels.push(model);
model.sortKey = this._sortKey++;
- model._cullingMask = CC_EDITOR ? 1 : this.cullingMask;
+ model._cullingMask = this.cullingMask;
model.setNode(this.node);
- model.addEffect(effect);
- model.addInputAssembler(iaRenderData.ia);
+ model.setEffect(effect);
+ model.setInputAssembler(ia);
this._renderScene.addModel(model);
},
- _commitComp (comp, assembler, cullingMask) {
- if (this.material._hash != comp._material._hash ||
- this.cullingMask !== cullingMask) {
- this._flush();
-
- this.node = assembler.useModel ? comp.node : this._dummyNode;
- this.material = comp._material;
- this.cullingMask = cullingMask;
+ terminate () {
+ if (cc.dynamicAtlasManager && cc.dynamicAtlasManager.enabled) {
+ cc.dynamicAtlasManager.update();
}
-
- assembler.fillBuffers(comp, this);
- },
-
- _commitIA (comp, assembler, cullingMask) {
- this._flush();
- this.cullingMask = cullingMask;
- this.material = comp._material;
- this.node = assembler.useModel ? comp.node : this._dummyNode;
-
- assembler.renderIA(comp, this);
- },
-
- visit (scene) {
- this.reset();
- this.walking = true;
- RenderFlow.render(scene);
-
- if (dynamicAtlasManager) {
- dynamicAtlasManager.update();
- }
-
+ // flush current rest Model
this._flush();
for (let key in _buffers) {
_buffers[key].uploadData();
}
+
this.walking = false;
},
getBuffer (type, vertextFormat) {
- if (!vertextFormat.name) {
- vertextFormat.name = idGenerater.getNewId();
- }
-
- let key = type + vertextFormat.name;
+ let key = type + vertextFormat.getHash();
let buffer = _buffers[key];
if (!buffer) {
if (type === 'mesh') {
@@ -239,6 +209,9 @@ RenderComponentWalker.prototype = {
else if (type === 'quad') {
buffer = new QuadBuffer(this, vertextFormat);
}
+ else if (type === 'spine') {
+ buffer = new SpineBuffer(this, vertextFormat);
+ }
else {
cc.error(`Not support buffer type [${type}]`);
return null;
@@ -251,4 +224,4 @@ RenderComponentWalker.prototype = {
}
}
-module.exports = RenderComponentWalker;
\ No newline at end of file
+module.exports = ModelBatcher;
diff --git a/cocos2d/core/renderer/webgl/quad-buffer.js b/cocos2d/core/renderer/webgl/quad-buffer.js
index b5835f8f6c2..ed92f177d9a 100644
--- a/cocos2d/core/renderer/webgl/quad-buffer.js
+++ b/cocos2d/core/renderer/webgl/quad-buffer.js
@@ -1,3 +1,28 @@
+/****************************************************************************
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
const MeshBuffer = require('./mesh-buffer');
let QuadBuffer = cc.Class({
@@ -17,7 +42,7 @@ let QuadBuffer = cc.Class({
buffer[idx++] = vertextID+2;
}
- let indicesData = new Uint16Array(this._iData.buffer, 0, count * 6 );
+ let indicesData = new Uint16Array(this._iData.buffer, 0, count * 6);
this._ib.update(0, indicesData);
},
@@ -33,6 +58,13 @@ let QuadBuffer = cc.Class({
this._dirty = false;
},
+ switchBuffer () {
+ this._super();
+ // upload index buffer data
+ let indicesData = new Uint16Array(this._iData.buffer, 0, this._initIDataCount);
+ this._ib.update(0, indicesData);
+ },
+
_reallocBuffer () {
this._reallocVData(true);
this._reallocIData();
diff --git a/cocos2d/core/renderer/webgl/render-data.js b/cocos2d/core/renderer/webgl/render-data.js
new file mode 100644
index 00000000000..35aeabd2675
--- /dev/null
+++ b/cocos2d/core/renderer/webgl/render-data.js
@@ -0,0 +1,72 @@
+import FlexBuffer from "./flex-buffer";
+import { vfmtPosUvColor } from './vertex-format';
+
+export default function RenderData () {
+ this.vDatas = [];
+ this.uintVDatas = [];
+ this.iDatas = [];
+ this.meshCount = 0;
+
+ this._infos = null;
+ this._flexBuffer = null;
+}
+
+cc.js.mixin(RenderData.prototype, {
+ init (assembler) {
+ },
+ clear () {
+ this.vDatas.length = 0;
+ this.iDatas.length = 0;
+ this.uintVDatas.length = 0;
+ this.meshCount = 0;
+
+ this._infos = null;
+
+ if (this._flexBuffer) {
+ this._flexBuffer.reset();
+ }
+ },
+
+ updateMesh (index, vertices, indices) {
+ this.vDatas[index] = vertices;
+ this.uintVDatas[index] = new Uint32Array(vertices.buffer, 0, vertices.length);
+ this.iDatas[index] = indices;
+
+ this.meshCount = this.vDatas.length;
+ },
+
+ updateMeshRange (verticesCount, indicesCount) {
+ },
+
+ createData (index, verticesFloats, indicesCount) {
+ let vertices = new Float32Array(verticesFloats);
+ let indices = new Uint16Array(indicesCount);
+ this.updateMesh(index, vertices, indices);
+ },
+
+ createQuadData (index, verticesFloats, indicesCount) {
+ this.createData(index, verticesFloats, indicesCount);
+ this.initQuadIndices(this.iDatas[index]);
+ },
+
+ createFlexData (index, verticesFloats, indicesCount, vfmt) {
+ vfmt = vfmt || vfmtPosUvColor;
+ this._flexBuffer = new FlexBuffer(this, index, verticesFloats, indicesCount, vfmt);
+ },
+
+ initQuadIndices(indices) {
+ let count = indices.length / 6;
+ for (let i = 0, idx = 0; i < count; i++) {
+ let vertextID = i * 4;
+ indices[idx++] = vertextID;
+ indices[idx++] = vertextID+1;
+ indices[idx++] = vertextID+2;
+ indices[idx++] = vertextID+1;
+ indices[idx++] = vertextID+3;
+ indices[idx++] = vertextID+2;
+ }
+ }
+})
+
+cc.RenderData = RenderData;
+
diff --git a/cocos2d/core/renderer/webgl/spine-buffer.js b/cocos2d/core/renderer/webgl/spine-buffer.js
new file mode 100644
index 00000000000..124be253cd4
--- /dev/null
+++ b/cocos2d/core/renderer/webgl/spine-buffer.js
@@ -0,0 +1,42 @@
+var SpineBuffer = cc.Class({
+ name: 'cc.SpineBuffer',
+ extends: require('./mesh-buffer'),
+
+ requestStatic (vertexCount, indiceCount) {
+
+ this.checkAndSwitchBuffer(vertexCount);
+
+ let byteOffset = this.byteOffset + vertexCount * this._vertexBytes;
+ let indiceOffset = this.indiceOffset + indiceCount;
+
+ let byteLength = this._vData.byteLength;
+ let indiceLength = this._iData.length;
+ if (byteOffset > byteLength || indiceOffset > indiceLength) {
+ while (byteLength < byteOffset || indiceLength < indiceOffset) {
+ this._initVDataCount *= 2;
+ this._initIDataCount *= 2;
+
+ byteLength = this._initVDataCount * 4;
+ indiceLength = this._initIDataCount;
+ }
+
+ this._reallocBuffer();
+ }
+
+ let offsetInfo = this._offsetInfo;
+ offsetInfo.vertexOffset = this.vertexOffset;
+ offsetInfo.indiceOffset = this.indiceOffset;
+ offsetInfo.byteOffset = this.byteOffset;
+ },
+
+ adjust (vertexCount, indiceCount) {
+ this.vertexOffset += vertexCount;
+ this.indiceOffset += indiceCount;
+
+ this.byteOffset = this.byteOffset + vertexCount * this._vertexBytes;
+
+ this._dirty = true;
+ }
+});
+
+cc.SpineBuffer = module.exports = SpineBuffer;
\ No newline at end of file
diff --git a/cocos2d/core/renderer/webgl/stencil-manager.js b/cocos2d/core/renderer/webgl/stencil-manager.js
deleted file mode 100644
index 20df8a7c95a..00000000000
--- a/cocos2d/core/renderer/webgl/stencil-manager.js
+++ /dev/null
@@ -1,173 +0,0 @@
-/****************************************************************************
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-const renderEngine = require('../render-engine');
-const gfx = renderEngine.gfx;
-
-// Stage types
-var Stage = cc.Enum({
- // Stencil disabled
- DISABLED: 0,
- // Clear stencil buffer
- CLEAR: 1,
- // Entering a new level, should handle new stencil
- ENTER_LEVEL: 2,
- // In content
- ENABLED: 3,
- // Exiting a level, should restore old stencil or disable
- EXIT_LEVEL: 4,
-});
-
-function StencilManager () {
- // todo: 8 is least Stencil depth supported by webGL device, it could be adjusted to vendor implementation value
- this._maxLevel = 8;
- // Current mask
- this._maskStack = [];
- // Current stage of process, DISABLED, ENTER_LEVEL, ENABLED, EXIT_LEVEL
- this.stage = Stage.DISABLED;
-}
-
-StencilManager.prototype = {
- constructor: StencilManager,
-
- reset () {
- // reset stack and stage
- this._maskStack.length = 0;
- this.stage = Stage.DISABLED;
- },
-
- handleEffect (effect) {
- let technique = effect.getTechnique('transparent');
- let passes = technique.passes;
- if (this.stage === Stage.DISABLED) {
- this.stage = Stage.DISABLED;
- for (let i = 0; i < passes.length; ++i) {
- let pass = passes[i];
- if (pass._stencilTest) {
- pass.disableStencilTest();
- }
- }
- return effect;
- }
-
- let mask, func, ref, stencilMask, writeMask, failOp,
- zFailOp = gfx.STENCIL_OP_KEEP,
- zPassOp = gfx.STENCIL_OP_KEEP;
-
- if (this.stage === Stage.ENABLED) {
- mask = this._maskStack[this._maskStack.length - 1];
- func = gfx.DS_FUNC_EQUAL;
- failOp = gfx.STENCIL_OP_KEEP;
- ref = this.getStencilRef();
- stencilMask = ref;
- writeMask = this.getWriteMask();
- }
- else {
- if (this.stage === Stage.CLEAR) {
- mask = this._maskStack[this._maskStack.length - 1];
- func = gfx.DS_FUNC_NEVER;
- failOp = mask.inverted ? gfx.STENCIL_OP_REPLACE : gfx.STENCIL_OP_ZERO;
- ref = this.getWriteMask();
- stencilMask = ref;
- writeMask = ref;
- }
- else if (this.stage === Stage.ENTER_LEVEL) {
- mask = this._maskStack[this._maskStack.length - 1];
- // Fill stencil mask
- func = gfx.DS_FUNC_NEVER;
- failOp = mask.inverted ? gfx.STENCIL_OP_ZERO : gfx.STENCIL_OP_REPLACE;
- ref = this.getWriteMask();
- stencilMask = ref;
- writeMask = ref;
-
- this.stage = Stage.ENABLED;
- }
- }
-
- for (let i = 0; i < passes.length; ++i) {
- let pass = passes[i];
- pass.setStencilFront(func, ref, stencilMask, failOp, zFailOp, zPassOp, writeMask);
- pass.setStencilBack(func, ref, stencilMask, failOp, zFailOp, zPassOp, writeMask);
- }
- return effect;
- },
-
- pushMask (mask) {
- if (this._maskStack.length + 1 > this._maxLevel) {
- cc.errorID(9000, this._maxLevel);
- }
- this._maskStack.push(mask);
- },
-
- clear () {
- this.stage = Stage.CLEAR;
- },
-
- enterLevel () {
- this.stage = Stage.ENTER_LEVEL;
- },
-
- exitMask () {
- if (this._maskStack.length === 0) {
- cc.errorID(9001);
- }
- this._maskStack.pop();
- if (this._maskStack.length === 0) {
- this.stage = Stage.DISABLED;
- }
- else {
- this.stage = Stage.ENABLED;
- }
- },
-
- getWriteMask () {
- return 0x01 << (this._maskStack.length - 1);
- },
-
- getExitWriteMask () {
- return 0x01 << this._maskStack.length;
- },
-
- getStencilRef () {
- let result = 0;
- for (let i = 0; i < this._maskStack.length; ++i) {
- result += (0x01 << i);
- }
- return result;
- },
-
- getInvertedRef () {
- let result = 0;
- for (let i = 0; i < this._maskStack.length - 1; ++i) {
- result += (0x01 << i);
- }
- return result;
- }
-};
-
-StencilManager.sharedManager = new StencilManager();
-StencilManager.Stage = Stage;
-
-module.exports = StencilManager;
\ No newline at end of file
diff --git a/cocos2d/core/renderer/webgl/vertex-format.js b/cocos2d/core/renderer/webgl/vertex-format.js
index 9947922a808..53e817a6b35 100644
--- a/cocos2d/core/renderer/webgl/vertex-format.js
+++ b/cocos2d/core/renderer/webgl/vertex-format.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -23,8 +23,7 @@
THE SOFTWARE.
****************************************************************************/
-const renderEngine = require('../render-engine');
-const gfx = renderEngine.gfx;
+import gfx from '../../../renderer/gfx';
var vfmt3D = new gfx.VertexFormat([
{ name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 3 },
@@ -32,6 +31,7 @@ var vfmt3D = new gfx.VertexFormat([
{ name: gfx.ATTR_COLOR, type: gfx.ATTR_TYPE_UINT8, num: 4, normalize: true },
]);
vfmt3D.name = 'vfmt3D';
+gfx.VertexFormat.XYZ_UV_Color = vfmt3D;
var vfmtPosUvColor = new gfx.VertexFormat([
{ name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
@@ -39,22 +39,42 @@ var vfmtPosUvColor = new gfx.VertexFormat([
{ name: gfx.ATTR_COLOR, type: gfx.ATTR_TYPE_UINT8, num: 4, normalize: true },
]);
vfmtPosUvColor.name = 'vfmtPosUvColor';
+gfx.VertexFormat.XY_UV_Color = vfmtPosUvColor;
+
+var vfmtPosUvTwoColor = new gfx.VertexFormat([
+ { name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
+ { name: gfx.ATTR_UV0, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
+ { name: gfx.ATTR_COLOR, type: gfx.ATTR_TYPE_UINT8, num: 4, normalize: true },
+ { name: gfx.ATTR_COLOR0, type: gfx.ATTR_TYPE_UINT8, num: 4, normalize: true },
+]);
+vfmtPosUvTwoColor.name = 'vfmtPosUvTwoColor';
+gfx.VertexFormat.XY_UV_Two_Color = vfmtPosUvTwoColor;
var vfmtPosUv = new gfx.VertexFormat([
{ name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
{ name: gfx.ATTR_UV0, type: gfx.ATTR_TYPE_FLOAT32, num: 2 }
]);
vfmtPosUv.name = 'vfmtPosUv';
+gfx.VertexFormat.XY_UV = vfmtPosUv;
var vfmtPosColor = new gfx.VertexFormat([
{ name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
{ name: gfx.ATTR_COLOR, type: gfx.ATTR_TYPE_UINT8, num: 4, normalize: true },
]);
vfmtPosColor.name = 'vfmtPosColor';
+gfx.VertexFormat.XY_Color = vfmtPosColor;
+
+var vfmtPos = new gfx.VertexFormat([
+ { name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
+]);
+vfmtPos.name = 'vfmtPos';
+gfx.VertexFormat.XY = vfmtPos;
module.exports = {
vfmt3D,
vfmtPosUvColor,
+ vfmtPosUvTwoColor,
vfmtPosUv,
- vfmtPosColor
+ vfmtPosColor,
+ vfmtPos
};
\ No newline at end of file
diff --git a/cocos2d/core/utils/CCPath.js b/cocos2d/core/utils/CCPath.js
index d0089bfe45c..98ef2abfc01 100644
--- a/cocos2d/core/utils/CCPath.js
+++ b/cocos2d/core/utils/CCPath.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -97,7 +97,7 @@ cc.path = /** @lends cc.path# */{
if (index > 0) pathStr = pathStr.substring(0, index);
var reg = /(\/|\\)([^\/\\]+)$/g;
var result = reg.exec(pathStr.replace(/(\/|\\)$/, ""));
- if (!result) return null;
+ if (!result) return pathStr;
var baseName = result[2];
if (extname && pathStr.substring(pathStr.length - extname.length).toLowerCase() === extname.toLowerCase())
return baseName.substring(0, baseName.length - extname.length);
diff --git a/cocos2d/core/utils/affine-transform.js b/cocos2d/core/utils/affine-transform.js
index 6b15db26a78..77d98df021b 100644
--- a/cocos2d/core/utils/affine-transform.js
+++ b/cocos2d/core/utils/affine-transform.js
@@ -157,12 +157,13 @@ AffineTransform.invert = function (out, t) {
* @return {AffineTransform} Out object with inverted result.
*/
AffineTransform.fromMat4 = function (out, mat) {
- out.a = mat.m00;
- out.b = mat.m01;
- out.c = mat.m04;
- out.d = mat.m05;
- out.tx = mat.m12;
- out.ty = mat.m13;
+ let matm = mat.m;
+ out.a = matm[0];
+ out.b = matm[1];
+ out.c = matm[4];
+ out.d = matm[5];
+ out.tx = matm[12];
+ out.ty = matm[13];
return out;
};
diff --git a/cocos2d/core/utils/base-node.js b/cocos2d/core/utils/base-node.js
index fdf76f50b6a..4e05da91ec6 100644
--- a/cocos2d/core/utils/base-node.js
+++ b/cocos2d/core/utils/base-node.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -145,14 +145,6 @@ var BaseNode = cc.Class({
_active: true,
- /**
- * @property _level
- * @type {Number}
- * @default 0
- * @private
- */
- _level: 0,
-
/**
* @property _components
* @type {Component[]}
@@ -213,6 +205,9 @@ var BaseNode = cc.Class({
return;
}
this._name = value;
+ if (CC_JSB && CC_NATIVERENDERER) {
+ this._proxy.setName(this._name);
+ }
},
},
@@ -333,9 +328,14 @@ var BaseNode = cc.Class({
* @private
*/
this.__eventTargets = [];
-
- this._renderFlag = RenderFlow.FLAG_TRANSFORM;
},
+ /**
+ * !#en The parent of the node.
+ * !#zh 该节点的父节点。
+ * @property {Node} parent
+ * @example
+ * cc.log("Node Parent: " + node.parent);
+ */
/**
* !#en Get parent of the node.
@@ -362,7 +362,7 @@ var BaseNode = cc.Class({
return;
}
if (CC_EDITOR && cc.engine && !cc.engine.isPlaying) {
- if (_Scene.DetectConflict.beforeAddChild(this)) {
+ if (_Scene.DetectConflict.beforeAddChild(this, value)) {
return;
}
}
@@ -378,7 +378,6 @@ var BaseNode = cc.Class({
if (CC_DEBUG && (value._objFlags & Deactivating)) {
cc.errorID(3821);
}
- this._level = value._level + 1;
eventManager._setDirtyForNode(this);
value._children.push(this);
value.emit && value.emit(CHILD_ADDED, this);
@@ -607,6 +606,7 @@ var BaseNode = cc.Class({
stack[index] = null;
// Do not repeatly visit child tree, just do post call and continue walk
if (afterChildren) {
+ if (parent === this._parent) break;
afterChildren = false;
}
else {
@@ -677,7 +677,6 @@ var BaseNode = cc.Class({
* 如果这个节点是一个孤节点,那么什么都不会发生。
* @method removeFromParent
* @param {Boolean} [cleanup=true] - true if all actions and callbacks on this node should be removed, false otherwise.
- * @see cc.Node#removeFromParentAndCleanup
* @example
* node.removeFromParent();
* node.removeFromParent(false);
@@ -783,9 +782,9 @@ var BaseNode = cc.Class({
* @param {Function|String} typeOrClassName
* @return {Component}
* @example
- * // get sprite component.
+ * // get sprite component
* var sprite = node.getComponent(cc.Sprite);
- * // get custom test calss.
+ * // get custom test class
* var test = node.getComponent("Test");
* @typescript
* getComponent(type: {prototype: T}): T
@@ -863,7 +862,7 @@ var BaseNode = cc.Class({
return components;
},
- _checkMultipleComp: CC_EDITOR && function (ctor) {
+ _checkMultipleComp: (CC_EDITOR || CC_PREVIEW) && function (ctor) {
var existing = this.getComponent(ctor._disallowMultiple);
if (existing) {
if (existing.constructor === ctor) {
@@ -928,7 +927,7 @@ var BaseNode = cc.Class({
return null;
}
- if (CC_EDITOR && constructor._disallowMultiple) {
+ if ((CC_EDITOR || CC_PREVIEW) && constructor._disallowMultiple) {
if (!this._checkMultipleComp(constructor)) {
return null;
}
@@ -1082,30 +1081,9 @@ var BaseNode = cc.Class({
}
},
- _disableChildComps () {
- // leave this._activeInHierarchy unmodified
- var i, len = this._components.length;
- for (i = 0; i < len; ++i) {
- var component = this._components[i];
- if (component._enabled) {
- cc.director._compScheduler.disableComp(component);
- }
- }
- // deactivate recursively
- for (i = 0, len = this._children.length; i < len; ++i) {
- var node = this._children[i];
- if (node._active) {
- node._disableChildComps();
- }
- }
- },
-
destroy () {
if (cc.Object.prototype.destroy.call(this)) {
- // disable hierarchy
- if (this._activeInHierarchy) {
- this._disableChildComps();
- }
+ this.active = false;
}
},
@@ -1129,8 +1107,7 @@ var BaseNode = cc.Class({
_onSetParent (value) {},
_onPostActivated () {},
- _onBatchRestored () {},
- _onBatchCreated () {},
+ _onBatchCreated (dontSyncChildPrefab) {},
_onHierarchyChanged (oldParent) {
var newParent = this._parent;
@@ -1161,12 +1138,23 @@ var BaseNode = cc.Class({
if (myPrefabInfo) {
if (newPrefabRoot) {
if (myPrefabInfo.root !== newPrefabRoot) {
- // change prefab
- PrefabUtils.unlinkPrefab(this);
- PrefabUtils.linkPrefab(newPrefabRoot._prefab.asset, newPrefabRoot, this);
+ if (myPrefabInfo.root === this) {
+ // nest prefab
+ myPrefabInfo.fileId || (myPrefabInfo.fileId = Editor.Utils.UuidUtils.uuid());
+ PrefabUtils.checkCircularReference(myPrefabInfo.root);
+ }
+ else {
+ // change prefab
+ PrefabUtils.linkPrefab(newPrefabRoot._prefab.asset, newPrefabRoot, this);
+ PrefabUtils.checkCircularReference(newPrefabRoot);
+ }
}
}
- else if (myPrefabInfo.root !== this) {
+ else if (myPrefabInfo.root === this) {
+ // nested prefab to root prefab
+ myPrefabInfo.fileId = ''; // root prefab doesn't have fileId
+ }
+ else {
// detach from prefab
PrefabUtils.unlinkPrefab(this);
}
@@ -1174,6 +1162,7 @@ var BaseNode = cc.Class({
else if (newPrefabRoot) {
// attach to prefab
PrefabUtils.linkPrefab(newPrefabRoot._prefab.asset, newPrefabRoot, this);
+ PrefabUtils.checkCircularReference(newPrefabRoot);
}
// conflict detection
@@ -1186,31 +1175,31 @@ var BaseNode = cc.Class({
}
},
- _instantiate (cloned) {
+ _instantiate (cloned, isSyncedNode) {
if (!cloned) {
cloned = cc.instantiate._clone(this, this);
}
- var thisPrefabInfo = this._prefab;
- if (CC_EDITOR && thisPrefabInfo) {
- if (this !== thisPrefabInfo.root) {
+ var newPrefabInfo = cloned._prefab;
+ if (CC_EDITOR && newPrefabInfo) {
+ if (cloned === newPrefabInfo.root) {
+ newPrefabInfo.fileId = '';
+ }
+ else {
var PrefabUtils = Editor.require('scene://utils/prefab');
- PrefabUtils.initClonedChildOfPrefab(cloned);
+ PrefabUtils.unlinkPrefab(cloned);
}
}
- var syncing = thisPrefabInfo && this === thisPrefabInfo.root && thisPrefabInfo.sync;
- if (syncing) {
- //if (thisPrefabInfo._synced) {
- // return clone;
- //}
- }
- else if (CC_EDITOR && cc.engine._isPlaying) {
- cloned._name += ' (Clone)';
+ if (CC_EDITOR && cc.engine._isPlaying) {
+ let syncing = newPrefabInfo && cloned === newPrefabInfo.root && newPrefabInfo.sync;
+ if (!syncing) {
+ cloned._name += ' (Clone)';
+ }
}
// reset and init
cloned._parent = null;
- cloned._onBatchRestored();
+ cloned._onBatchCreated(isSyncedNode);
return cloned;
},
@@ -1326,7 +1315,7 @@ if(CC_EDITOR) {
}
// Define public getter and setter methods to ensure api compatibility.
-var SameNameGetSets = ['name', 'children', 'childrenCount',];
+var SameNameGetSets = ['parent', 'name', 'children', 'childrenCount',];
misc.propertyDefine(BaseNode, SameNameGetSets, {});
if (CC_DEV) {
diff --git a/cocos2d/core/utils/binary-search.js b/cocos2d/core/utils/binary-search.js
index fa5b4a847a8..02d1ceb552c 100644
--- a/cocos2d/core/utils/binary-search.js
+++ b/cocos2d/core/utils/binary-search.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/utils/blend-func.js b/cocos2d/core/utils/blend-func.js
new file mode 100644
index 00000000000..fd71619a342
--- /dev/null
+++ b/cocos2d/core/utils/blend-func.js
@@ -0,0 +1,105 @@
+
+const RenderComponent = require('../components/CCRenderComponent');
+const BlendFactor = require('../platform/CCMacro').BlendFactor;
+const gfx = require('../../renderer/gfx');
+
+/**
+ * !#en
+ * Helper class for setting material blend function.
+ * !#zh
+ * 设置材质混合模式的辅助类。
+ * @class BlendFunc
+ */
+let BlendFunc = cc.Class({
+ properties: {
+ _srcBlendFactor: BlendFactor.SRC_ALPHA,
+ _dstBlendFactor: BlendFactor.ONE_MINUS_SRC_ALPHA,
+
+ /**
+ * !#en specify the source Blend Factor, this will generate a custom material object, please pay attention to the memory cost.
+ * !#zh 指定原图的混合模式,这会克隆一个新的材质对象,注意这带来的开销
+ * @property srcBlendFactor
+ * @type {macro.BlendFactor}
+ * @example
+ * sprite.srcBlendFactor = cc.macro.BlendFactor.ONE;
+ */
+ srcBlendFactor: {
+ get () {
+ return this._srcBlendFactor;
+ },
+ set (value) {
+ if (this._srcBlendFactor === value) return;
+ this._srcBlendFactor = value;
+ this._updateBlendFunc(true);
+ this._onBlendChanged && this._onBlendChanged();
+ },
+ animatable: false,
+ type: BlendFactor,
+ tooltip: CC_DEV && 'i18n:COMPONENT.sprite.src_blend_factor',
+ visible: true
+ },
+
+ /**
+ * !#en specify the destination Blend Factor.
+ * !#zh 指定目标的混合模式
+ * @property dstBlendFactor
+ * @type {macro.BlendFactor}
+ * @example
+ * sprite.dstBlendFactor = cc.macro.BlendFactor.ONE;
+ */
+ dstBlendFactor: {
+ get () {
+ return this._dstBlendFactor;
+ },
+ set (value) {
+ if (this._dstBlendFactor === value) return;
+ this._dstBlendFactor = value;
+ this._updateBlendFunc(true);
+ },
+ animatable: false,
+ type: BlendFactor,
+ tooltip: CC_DEV && 'i18n:COMPONENT.sprite.dst_blend_factor',
+ visible: true
+ },
+ },
+
+ setMaterial (index, material) {
+ let materialVar = RenderComponent.prototype.setMaterial.call(this, index, material);
+
+ if (this._srcBlendFactor !== BlendFactor.SRC_ALPHA || this._dstBlendFactor !== BlendFactor.ONE_MINUS_SRC_ALPHA) {
+ this._updateMaterialBlendFunc(materialVar);
+ }
+
+ return materialVar;
+ },
+
+ _updateMaterial () {
+ this._updateBlendFunc();
+ },
+
+ _updateBlendFunc (force) {
+ if (!force) {
+ if (this._srcBlendFactor === BlendFactor.SRC_ALPHA && this._dstBlendFactor === BlendFactor.ONE_MINUS_SRC_ALPHA) {
+ return;
+ }
+ }
+
+ let materials = this.getMaterials();
+ for (let i = 0; i < materials.length; i++) {
+ let material = materials[i];
+ this._updateMaterialBlendFunc(material);
+ }
+ },
+
+ _updateMaterialBlendFunc (material) {
+ material.setBlend(
+ true,
+ gfx.BLEND_FUNC_ADD,
+ this._srcBlendFactor, this._dstBlendFactor,
+ gfx.BLEND_FUNC_ADD,
+ this._srcBlendFactor, this._dstBlendFactor
+ );
+ },
+});
+
+module.exports = cc.BlendFunc = BlendFunc;
diff --git a/cocos2d/core/utils/decode-uuid.js b/cocos2d/core/utils/decode-uuid.js
index 13e96baceaf..3af97efc9fa 100644
--- a/cocos2d/core/utils/decode-uuid.js
+++ b/cocos2d/core/utils/decode-uuid.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/utils/find.js b/cocos2d/core/utils/find.js
index ea42a19c2fc..c52772f98c4 100644
--- a/cocos2d/core/utils/find.js
+++ b/cocos2d/core/utils/find.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -38,7 +38,7 @@
*/
cc.find = module.exports = function (path, referenceNode) {
if (path == null) {
- cc.errorID(5600);
+ cc.errorID(3814);
return null;
}
if (!referenceNode) {
diff --git a/cocos2d/core/utils/gray-sprite-state.js b/cocos2d/core/utils/gray-sprite-state.js
new file mode 100644
index 00000000000..d7a9c580757
--- /dev/null
+++ b/cocos2d/core/utils/gray-sprite-state.js
@@ -0,0 +1,77 @@
+
+import MaterialVariant from '../assets/material/material-variant';
+const Material = require('../assets/material/CCMaterial');
+
+/**
+ * An internal helper class for switching render component's material between normal sprite material and gray sprite material.
+ * @class GraySpriteState
+ */
+let GraySpriteState = cc.Class({
+ properties: {
+ _normalMaterial: null,
+
+ /**
+ * !#en The normal material.
+ * !#zh 正常状态的材质。
+ * @property normalMaterial
+ * @type {Material}
+ * @default null
+ */
+ normalMaterial: {
+ get () {
+ return this._normalMaterial;
+ },
+ set (val) {
+ this._normalMaterial = val;
+ this._updateDisabledState && this._updateDisabledState();
+ },
+ type: Material,
+ tooltip: CC_DEV && 'i18n:COMPONENT.button.normal_material',
+ animatable: false
+ },
+
+ _grayMaterial: null,
+
+ /**
+ * !#en The gray material.
+ * !#zh 置灰状态的材质。
+ * @property grayMaterial
+ * @type {Material}
+ * @default null
+ */
+ grayMaterial: {
+ get () {
+ return this._grayMaterial;
+ },
+ set (val) {
+ this._grayMaterial = val;
+ this._updateDisabledState && this._updateDisabledState();
+ },
+ type: Material,
+ tooltip: CC_DEV && 'i18n:COMPONENT.button.gray_material',
+ animatable: false
+ }
+ },
+
+ _switchGrayMaterial (useGrayMaterial, renderComp) {
+ let material;
+ if (useGrayMaterial) {
+ material = this._grayMaterial;
+ if (!material) {
+ material = Material.getBuiltinMaterial('2d-gray-sprite');
+ }
+ material = this._grayMaterial = MaterialVariant.create(material, renderComp);
+ }
+ else {
+ material = this._normalMaterial;
+ if (!material) {
+ material = Material.getBuiltinMaterial('2d-sprite', renderComp);
+ }
+ material = this._normalMaterial = MaterialVariant.create(material, renderComp);
+ }
+
+ renderComp.setMaterial(0, material);
+ }
+});
+
+module.exports = GraySpriteState;
diff --git a/cocos2d/core/utils/html-text-parser.js b/cocos2d/core/utils/html-text-parser.js
index 6cdce9ec8f5..75acfa0dff1 100644
--- a/cocos2d/core/utils/html-text-parser.js
+++ b/cocos2d/core/utils/html-text-parser.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -24,8 +24,8 @@
THE SOFTWARE.
****************************************************************************/
-var eventRegx = /^(click)(\s)*=/;
-var imageAttrReg = /(\s)*src(\s)*=|(\s)*height(\s)*=|(\s)*width(\s)*=|(\s)*click(\s)*=/;
+var eventRegx = /^(click)(\s)*=|(param)(\s)*=/;
+var imageAttrReg = /(\s)*src(\s)*=|(\s)*height(\s)*=|(\s)*width(\s)*=|(\s)*align(\s)*=|(\s)*offset(\s)*=|(\s)*click(\s)*=|(\s)*param(\s)*=/;
/**
* A utils class for parsing HTML texts. The parsed results will be an object array.
*/
@@ -37,6 +37,7 @@ var HtmlTextParser = function() {
this._specialSymbolArray.push([/&/g, '&']);
this._specialSymbolArray.push([/"/g, '"']);
this._specialSymbolArray.push([/'/g, '\'']);
+ this._specialSymbolArray.push([/ /g, ' ']);
};
HtmlTextParser.prototype = {
@@ -48,25 +49,36 @@ HtmlTextParser.prototype = {
var startIndex = 0;
var length = htmlString.length;
while (startIndex < length) {
- var tagBeginIndex = htmlString.indexOf('<', startIndex);
+ var tagEndIndex = htmlString.indexOf('>', startIndex);
+ var tagBeginIndex = -1;
+ if (tagEndIndex >= 0) {
+ tagBeginIndex = htmlString.lastIndexOf('<', tagEndIndex);
+ var noTagBegin = tagBeginIndex < (startIndex - 1);
+
+ if (noTagBegin) {
+ tagBeginIndex = htmlString.indexOf('<', tagEndIndex + 1);
+ tagEndIndex = htmlString.indexOf('>', tagBeginIndex + 1);
+ }
+ }
+
if (tagBeginIndex < 0) {
this._stack.pop();
this._processResult(htmlString.substring(startIndex));
startIndex = length;
} else {
- this._processResult(htmlString.substring(startIndex, tagBeginIndex));
-
- var tagEndIndex = htmlString.indexOf('>', startIndex);
+ var newStr = htmlString.substring(startIndex, tagBeginIndex);
+ var tagStr = htmlString.substring(tagBeginIndex + 1, tagEndIndex);
+ if (tagStr === "") newStr = htmlString.substring(startIndex, tagEndIndex + 1);
+ this._processResult(newStr);
if (tagEndIndex === -1) {
// cc.error('The HTML tag is invalid!');
tagEndIndex = tagBeginIndex;
} else if (htmlString.charAt(tagBeginIndex + 1) === '\/'){
this._stack.pop();
} else {
- this._addToStack(htmlString.substring(tagBeginIndex + 1, tagEndIndex));
+ this._addToStack(tagStr);
}
startIndex = tagEndIndex + 1;
-
}
}
@@ -143,29 +155,43 @@ HtmlTextParser.prototype = {
tagName = tagName.toLocaleLowerCase();
attribute = remainingArgument.substring(nextSpace).trim();
+ if ( tagValue.endsWith( '\/' ) ) tagValue = tagValue.slice( 0, -1 );
if (tagName === "src") {
- obj.isImage = true
- if( tagValue.endsWith( '\/' ) ) tagValue = tagValue.substring( 0, tagValue.length - 1 );
- if( tagValue.indexOf('\'')===0 ) {
- isValidImageTag = true;
- tagValue = tagValue.substring( 1, tagValue.length - 1 );
- } else if( tagValue.indexOf('"')===0 ) {
- isValidImageTag = true;
- tagValue = tagValue.substring( 1, tagValue.length - 1 );
+ switch (tagValue.charCodeAt(0)) {
+ case 34: // "
+ case 39: // '
+ isValidImageTag = true;
+ tagValue = tagValue.slice(1, -1);
+ break;
}
+ obj.isImage = true;
obj.src = tagValue;
} else if (tagName === "height") {
obj.imageHeight = parseInt(tagValue);
} else if (tagName === "width") {
obj.imageWidth = parseInt(tagValue);
+ } else if (tagName === "align") {
+ switch (tagValue.charCodeAt(0)) {
+ case 34: // "
+ case 39: // '
+ tagValue = tagValue.slice(1, -1);
+ break;
+ }
+ obj.imageAlign = tagValue.toLocaleLowerCase();
+ } else if (tagName === "offset") {
+ obj.imageOffset = tagValue;
} else if (tagName === "click") {
obj.event = this._processEventHandler(tagName + "=" + tagValue);
}
+
+ if (obj.event && tagName === 'param') {
+ obj.event.param = tagValue.replace(/^\"|\"$/g, '');
+ }
+
header = attribute.match(imageAttrReg);
}
- if( isValidImageTag && obj.isImage )
- {
+ if( isValidImageTag && obj.isImage ) {
this._resultObjectArray.push({text: "", style: obj});
}
@@ -178,7 +204,7 @@ HtmlTextParser.prototype = {
attribute = header[0].substring("outline".length).trim();
var defaultOutlineObject = {color: "#ffffff", width: 1};
if (attribute) {
- var outlineAttrReg = /(\s)*color(\s)*=|(\s)*width(\s)*=|(\s)*click(\s)*=/;
+ var outlineAttrReg = /(\s)*color(\s)*=|(\s)*width(\s)*=|(\s)*click(\s)*=|(\s)*param(\s)*=/;
header = attribute.match(outlineAttrReg);
var tagValue;
while (header) {
@@ -204,6 +230,11 @@ HtmlTextParser.prototype = {
} else if (tagName === "width") {
defaultOutlineObject.width = parseInt(tagValue);
}
+
+ if (obj.event && tagName === 'param') {
+ obj.event.param = tagValue.replace(/^\"|\"$/g, '');
+ }
+
header = attribute.match(outlineAttrReg);
}
}
@@ -232,7 +263,6 @@ HtmlTextParser.prototype = {
obj.event = eventObj;
}
-
return obj;
},
@@ -331,4 +361,4 @@ if (CC_TEST) {
cc._Test.HtmlTextParser = HtmlTextParser;
}
-module.exports = HtmlTextParser;
\ No newline at end of file
+module.exports = HtmlTextParser;
diff --git a/cocos2d/core/utils/index.js b/cocos2d/core/utils/index.js
index e97dc29341b..892b80d5cfc 100644
--- a/cocos2d/core/utils/index.js
+++ b/cocos2d/core/utils/index.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/utils/math-pools.js b/cocos2d/core/utils/math-pools.js
index 23697c4d4ce..35947350481 100644
--- a/cocos2d/core/utils/math-pools.js
+++ b/cocos2d/core/utils/math-pools.js
@@ -1,7 +1,7 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -24,20 +24,19 @@
****************************************************************************/
const js = require('../platform/js');
-const renderEngine = require('../renderer/render-engine');
// const Vec2 = require('../value-types/vec2');
// const Vec3 = require('../value-types/vec3');
-// const Quat = require('../value-types/quat');
-const math = renderEngine.math;
+const Quat = require('../value-types/quat');
+const Mat4 = require('../value-types/mat4');
var mat4Pool = new js.Pool(128);
mat4Pool.get = function () {
var matrix = this._get();
if (matrix) {
- math.mat4.identity(matrix);
+ Mat4.identity(matrix);
}
else {
- matrix = math.mat4.create();
+ matrix = new Mat4();
}
return matrix;
};
@@ -68,15 +67,15 @@ mat4Pool.get = function () {
var quatPool = new js.Pool(64);
quatPool.get = function () {
- var quat = this._get();
- if (quat) {
- quat.x = quat.y = quat.z = 0;
- quat.w = 1;
+ var q = this._get();
+ if (q) {
+ q.x = q.y = q.z = 0;
+ q.w = 1;
}
else {
- quat = math.quat.create();
+ q = new Quat();
}
- return quat;
+ return q;
};
module.exports = {
diff --git a/cocos2d/core/utils/misc.js b/cocos2d/core/utils/misc.js
index ea5e4fef247..cb0eb877769 100644
--- a/cocos2d/core/utils/misc.js
+++ b/cocos2d/core/utils/misc.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -98,23 +98,14 @@ misc.NextPOT = function (x) {
if (CC_EDITOR) {
// use anonymous function here to ensure it will not being hoisted without CC_EDITOR
- misc.tryCatchFunctor_EDITOR = function (funcName, forwardArgs, afterCall, bindArg) {
- function call_FUNC_InTryCatch (_R_ARGS_) {
- try {
- target._FUNC_(_U_ARGS_);
- }
- catch (e) {
- cc._throw(e);
- }
- _AFTER_CALL_
- }
- // use evaled code to generate named function
- return Function('arg', 'return ' + call_FUNC_InTryCatch
- .toString()
- .replace(/_FUNC_/g, funcName)
- .replace('_R_ARGS_', 'target' + (forwardArgs ? ', ' + forwardArgs : ''))
- .replace('_U_ARGS_', forwardArgs || '')
- .replace('_AFTER_CALL_', afterCall || ''))(bindArg);
+ misc.tryCatchFunctor_EDITOR = function (funcName) {
+ return Function('target',
+ 'try {\n' +
+ ' target.' + funcName + '();\n' +
+ '}\n' +
+ 'catch (e) {\n' +
+ ' cc._throw(e);\n' +
+ '}');
};
}
@@ -199,7 +190,7 @@ misc.clamp01 = function (value) {
* @param {Number} b number B
* @param {Number} r ratio between 0 and 1
* @return {Number}
- * @example {@link utils/api/engine/docs/cocos2d/core/platform/CCMacro/lerp.js}
+ * @example {@link cocos2d/core/platform/CCMacro/lerp.js}
*/
misc.lerp = function (a, b, r) {
return a + (b - a) * r;
diff --git a/cocos2d/core/utils/mutable-forward-iterator.js b/cocos2d/core/utils/mutable-forward-iterator.js
index 6581ee9969a..876af049a51 100644
--- a/cocos2d/core/utils/mutable-forward-iterator.js
+++ b/cocos2d/core/utils/mutable-forward-iterator.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
diff --git a/cocos2d/core/utils/pool.js b/cocos2d/core/utils/pool.js
new file mode 100644
index 00000000000..7a643c8f144
--- /dev/null
+++ b/cocos2d/core/utils/pool.js
@@ -0,0 +1,22 @@
+
+export default class Pool {
+ enabled = false;
+ count = 0;
+ maxSize = 1024;
+
+ get () {
+
+ }
+ put () {
+
+ }
+ clear () {
+
+ }
+}
+
+cc.pool = {};
+
+Pool.register = function (name, pool) {
+ cc.pool[name] = pool;
+}
diff --git a/cocos2d/core/utils/prefab-helper.js b/cocos2d/core/utils/prefab-helper.js
index 65c587bcffd..7779687bf77 100644
--- a/cocos2d/core/utils/prefab-helper.js
+++ b/cocos2d/core/utils/prefab-helper.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -24,42 +24,24 @@
THE SOFTWARE.
****************************************************************************/
-var math = require("../renderer").renderEngine.math;
-
cc._PrefabInfo = cc.Class({
name: 'cc.PrefabInfo',
// extends: require('../platform/CCObject'),
properties: {
- // the most top node of this prefab in the scene
+ // the most top node of this prefab
root: null,
// 所属的 prefab 资源对象 (cc.Prefab)
// In Editor, only asset._uuid is usable because asset will be changed.
asset: null,
- // 用来标识别该节点在 prefab 资源中的位置,因此这个 ID 只需要保证在 Assets 里不重复就行
+ // To identify the node in the prefab asset, so only needs to be unique.
+ // Not available in the root node.
fileId: '',
// Indicates whether this node should always synchronize with the prefab asset, only available in the root node
sync: false,
-
- // Indicates whether this node is synchronized, only available in the root node
- _synced: {
- default: false,
- serializable: false
- },
},
- // _instantiate (cloned) {
- // if (!cloned) {
- // cloned = new cc._PrefabInfo();
- // }
- // cloned.root = this.root;
- // cloned.asset = this.asset;
- // cloned.fileId = this.fileId;
- // cloned.sync = this.sync;
- // cloned._synced = this._synced;
- // return cloned;
- // }
});
// prefab helper function
@@ -67,9 +49,7 @@ module.exports = {
// update node to make it sync with prefab
syncWithPrefab: function (node) {
var _prefab = node._prefab;
- // non-reentrant
- _prefab._synced = true;
- //
+
if (!_prefab.asset) {
if (CC_EDITOR) {
var NodeUtils = Editor.require('scene://utils/node');
@@ -91,11 +71,14 @@ module.exports = {
var _id = node._id;
var _name = node._name;
var _active = node._active;
- var x = node._position.x;
- var y = node._position.y;
- var _quat = node._quat;
+ var eulerAnglesX = node._eulerAngles.x;
+ var eulerAnglesY = node._eulerAngles.y;
+ var eulerAnglesZ = node._eulerAngles.z;
var _localZOrder = node._localZOrder;
- var _globalZOrder = node._globalZOrder;
+ var trs = node._trs;
+ var x = trs[0];
+ var y = trs[1];
+ var z = trs[2];
// instantiate prefab
cc.game._isCloning = true;
@@ -105,7 +88,6 @@ module.exports = {
else {
// root in prefab asset is always synced
var prefabRoot = _prefab.asset.data;
- prefabRoot._prefab._synced = true;
// use node as the instantiated prefabRoot to make references to prefabRoot in prefab redirect to node
prefabRoot._iN$t = node;
@@ -122,10 +104,13 @@ module.exports = {
node._prefab = _prefab;
node._name = _name;
node._active = _active;
- node._position.x = x;
- node._position.y = y;
- math.quat.copy(node._quat, _quat);
node._localZOrder = _localZOrder;
- node._globalZOrder = _globalZOrder;
+ trs = node._trs;
+ trs[0] = x;
+ trs[1] = y;
+ trs[2] = z;
+ node._eulerAngles.x = eulerAnglesX;
+ node._eulerAngles.y = eulerAnglesY;
+ node._eulerAngles.z = eulerAnglesZ;
}
};
diff --git a/cocos2d/core/utils/profiler/CCProfiler.js b/cocos2d/core/utils/profiler/CCProfiler.js
index 01701a64abd..5a75d2c071e 100644
--- a/cocos2d/core/utils/profiler/CCProfiler.js
+++ b/cocos2d/core/utils/profiler/CCProfiler.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -31,90 +31,17 @@ const PerfCounter = require('./perf-counter');
let _showFPS = false;
let _fontSize = 15;
-let _atlas = null;
let _stats = null;
let _rootNode = null;
let _label = null;
-function generateAtlas () {
- if (_atlas) return;
-
- let textureWidth = 256,
- textureHeight = 256;
-
- let canvas = document.createElement("canvas");
- canvas.style.width = canvas.width = textureWidth;
- canvas.style.height = canvas.height = textureHeight;
-
- // comment out this to show atlas
- // document.body.appendChild(canvas)
-
- let ctx = canvas.getContext('2d');
- ctx.font = `${_fontSize}px Arial`;
- ctx.textBaseline = 'top';
- ctx.textAlign = 'left';
- ctx.fillStyle = '#fff';
-
- let space = 2;
- let x = space;
- let y = space;
- let lineHeight = _fontSize;
-
- _atlas = new cc.LabelAtlas();
- _atlas._fntConfig = {
- atlasName: 'profiler-arial',
- commonHeight: lineHeight,
- fontSize: _fontSize,
- kerningDict: {},
- fontDefDictionary: {}
- };
-
- _atlas._name = 'profiler-arial';
- _atlas.fontSize = _fontSize;
-
- let dict = _atlas._fntConfig.fontDefDictionary;
-
- for (let i = 32; i <= 126; i++) {
- let char = String.fromCharCode(i);
- let width = ctx.measureText(char).width;
-
- if ((x + width) >= textureWidth) {
- x = space;
- y += lineHeight + space;
- }
- ctx.fillText(char, x, y);
-
- dict[i] = {
- xAdvance: width,
- xOffset: 0,
- yOffset: 0,
- rect: {
- x: x,
- y: y,
- width: width,
- height: lineHeight
- }
- }
-
- x += width + space;
- }
-
- let texture = new cc.Texture2D();
- texture.initWithElement(canvas);
-
- let spriteFrame = new cc.SpriteFrame();
- spriteFrame.setTexture(texture);
-
- _atlas.spriteFrame = spriteFrame;
-}
-
function generateStats () {
if (_stats) return;
_stats = {
- frame: { desc: 'Frame time (ms)', min: 0, max: 50, average: 500 },
fps: { desc: 'Framerate (FPS)', below: 30, average: 500 },
- draws: { desc: 'Draw call' },
+ draws: { desc: 'Draw Call' },
+ frame: { desc: 'Frame time (ms)', min: 0, max: 50, average: 500 },
logic: { desc: 'Game Logic (ms)', min: 0, max: 50, average: 500, color: '#080' },
render: { desc: 'Renderer (ms)', min: 0, max: 50, average: 500, color: '#f90' },
mode: { desc: cc.game.renderType === cc.game.RENDER_TYPE_WEBGL ? 'WebGL' : 'Canvas', min: 1 }
@@ -141,22 +68,25 @@ function generateNode () {
let left = new cc.Node('LEFT-PANEL');
left.anchorX = left.anchorY = 0;
- left.parent = _rootNode;
let leftLabel = left.addComponent(cc.Label);
- leftLabel.font = _atlas;
leftLabel.fontSize = _fontSize;
leftLabel.lineHeight = _fontSize;
+ left.parent = _rootNode;
let right = new cc.Node('RIGHT-PANEL');
right.anchorX = 1;
right.anchorY = 0;
right.x = 200;
- right.parent = _rootNode;
let rightLabel = right.addComponent(cc.Label);
rightLabel.horizontalAlign = cc.Label.HorizontalAlign.RIGHT;
- rightLabel.font = _atlas;
rightLabel.fontSize = _fontSize;
rightLabel.lineHeight = _fontSize;
+ right.parent = _rootNode;
+ if (cc.sys.platform !== cc.sys.BAIDU_GAME_SUB &&
+ cc.sys.platform !== cc.sys.WECHAT_GAME_SUB) {
+ leftLabel.cacheMode = cc.Label.CacheMode.CHAR;
+ rightLabel.cacheMode = cc.Label.CacheMode.CHAR;
+ }
_label = {
left: leftLabel,
@@ -207,8 +137,10 @@ function afterDraw () {
right += stat._counter.human() + '\n';
}
- _label.left.string = left;
- _label.right.string = right;
+ if (_label) {
+ _label.left.string = left;
+ _label.right.string = right;
+ }
}
cc.profiler = module.exports = {
@@ -231,7 +163,6 @@ cc.profiler = module.exports = {
showStats () {
if (!_showFPS) {
- generateAtlas();
generateStats();
if (_rootNode) {
@@ -244,4 +175,4 @@ cc.profiler = module.exports = {
_showFPS = true;
}
}
-}
\ No newline at end of file
+}
diff --git a/cocos2d/core/utils/text-utils.js b/cocos2d/core/utils/text-utils.js
index 6714142a8f1..8fc23cd5c2f 100644
--- a/cocos2d/core/utils/text-utils.js
+++ b/cocos2d/core/utils/text-utils.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -24,19 +24,134 @@
THE SOFTWARE.
****************************************************************************/
+import js from '../platform/js'
+
+// Draw text the textBaseline ratio (Can adjust the appropriate baseline ratio based on the platform)
+let _BASELINE_RATIO = 0.26;
+let _BASELINE_OFFSET = 0;
+if (CC_RUNTIME) {
+ _BASELINE_OFFSET = _BASELINE_RATIO * 2 / 3;
+}
+
+const MAX_CACHE_SIZE = 100;
+
+let pool = new js.Pool(2);
+pool.get = function () {
+ var node = this._get() || {
+ key: null,
+ value: null,
+ prev: null,
+ next: null
+ };
+
+ return node;
+};
+
+function LRUCache(size) {
+ this.count = 0;
+ this.limit = size;
+ this.datas = {};
+ this.head = null;
+ this.tail = null;
+}
+
+LRUCache.prototype.moveToHead = function (node) {
+ node.next = this.head;
+ node.prev = null;
+ if (this.head !== null)
+ this.head.prev = node;
+ this.head = node;
+ if (this.tail === null)
+ this.tail = node;
+ this.count++;
+ this.datas[node.key] = node;
+}
+
+LRUCache.prototype.put = function (key, value) {
+ const node = pool.get();
+ node.key = key;
+ node.value = value;
+
+ if (this.count >= this.limit) {
+ let discard = this.tail;
+ delete this.datas[discard.key];
+ this.count--;
+ this.tail = discard.prev;
+ this.tail.next = null;
+ discard.prev = null;
+ discard.next = null;
+ pool.put(discard);
+ }
+ this.moveToHead(node);
+}
+
+LRUCache.prototype.remove = function (node) {
+ if (node.prev !== null) {
+ node.prev.next = node.next;
+ } else {
+ this.head = node.next;
+ }
+ if (node.next !== null) {
+ node.next.prev = node.prev;
+ } else {
+ this.tail = node.prev;
+ }
+ delete this.datas[node.key];
+ this.count--;
+}
+
+LRUCache.prototype.get = function (key) {
+ const node = this.datas[key];
+ if (node) {
+ this.remove(node);
+ this.moveToHead(node);
+ return node.value;
+ }
+ return null;
+}
+
+LRUCache.prototype.clear = function () {
+ this.count = 0;
+ this.datas = {};
+ this.head = null;
+ this.tail = null;
+}
+
+LRUCache.prototype.has = function (key) {
+ return !!this.datas[key];
+}
+
+LRUCache.prototype.delete = function (key) {
+ const node = this.datas[key];
+ this.remove(node);
+}
+
+let measureCache = new LRUCache(MAX_CACHE_SIZE);
+
var textUtils = {
+
+ BASELINE_RATIO: _BASELINE_RATIO,
+ MIDDLE_RATIO: (_BASELINE_RATIO + 1) / 2 - _BASELINE_RATIO,
+ BASELINE_OFFSET: _BASELINE_OFFSET,
+
label_wordRex : /([a-zA-Z0-9ÄÖÜäöüßéèçàùêâîôûа-яА-ЯЁё]+|\S)/,
label_symbolRex : /^[!,.:;'}\]%\?>、‘“》?。,!]/,
label_lastWordRex : /([a-zA-Z0-9ÄÖÜäöüßéèçàùêâîôûаíìÍÌïÁÀáàÉÈÒÓòóŐőÙÚŰúűñÑæÆœŒÃÂãÔõěščřžýáíéóúůťďňĚŠČŘŽÁÍÉÓÚŤżźśóńłę湯ŹŚÓŃŁĘĆĄ-яА-ЯЁё]+|\S)$/,
label_lastEnglish : /[a-zA-Z0-9ÄÖÜäöüßéèçàùêâîôûаíìÍÌïÁÀáàÉÈÒÓòóŐőÙÚŰúűñÑæÆœŒÃÂãÔõěščřžýáíéóúůťďňĚŠČŘŽÁÍÉÓÚŤżźśóńłę湯ŹŚÓŃŁĘĆĄ-яА-ЯЁё]+$/,
label_firstEnglish : /^[a-zA-Z0-9ÄÖÜäöüßéèçàùêâîôûаíìÍÌïÁÀáàÉÈÒÓòóŐőÙÚŰúűñÑæÆœŒÃÂãÔõěščřžýáíéóúůťďňĚŠČŘŽÁÍÉÓÚŤżźśóńłę湯ŹŚÓŃŁĘĆĄ-яА-ЯЁё]/,
+ // The unicode standard will never assign a character from code point 0xD800 to 0xDFFF
+ // high surrogate (0xD800-0xDBFF) and low surrogate(0xDC00-0xDFFF) combines to a character on the Supplementary Multilingual Plane
+ // reference: https://en.wikipedia.org/wiki/UTF-16
+ highSurrogateRex: /[\uD800-\uDBFF]/,
+ lowSurrogateRex: /[\uDC00-\uDFFF]/,
label_wrapinspection : true,
+ __CHINESE_REG: /^[\u4E00-\u9FFF\u3400-\u4DFF]+$/,
+ __JAPANESE_REG: /[\u3000-\u303F]|[\u3040-\u309F]|[\u30A0-\u30FF]|[\uFF00-\uFFEF]|[\u4E00-\u9FAF]|[\u2605-\u2606]|[\u2190-\u2195]|\u203B/g,
+ __KOREAN_REG: /^[\u1100-\u11FF]|[\u3130-\u318F]|[\uA960-\uA97F]|[\uAC00-\uD7AF]|[\uD7B0-\uD7FF]+$/,
+
isUnicodeCJK: function(ch) {
- var __CHINESE_REG = /^[\u4E00-\u9FFF\u3400-\u4DFF]+$/;
- var __JAPANESE_REG = /[\u3000-\u303F]|[\u3040-\u309F]|[\u30A0-\u30FF]|[\uFF00-\uFFEF]|[\u4E00-\u9FAF]|[\u2605-\u2606]|[\u2190-\u2195]|\u203B/g;
- var __KOREAN_REG = /^[\u1100-\u11FF]|[\u3130-\u318F]|[\uA960-\uA97F]|[\uAC00-\uD7AF]|[\uD7B0-\uD7FF]+$/;
- return __CHINESE_REG.test(ch) || __JAPANESE_REG.test(ch) || __KOREAN_REG.test(ch);
+ return this.__CHINESE_REG.test(ch) || this.__JAPANESE_REG.test(ch) || this.__KOREAN_REG.test(ch);
},
//Checking whether the character is a whitespace
@@ -45,9 +160,48 @@ var textUtils = {
return ((ch >= 9 && ch <= 13) || ch === 32 || ch === 133 || ch === 160 || ch === 5760 || (ch >= 8192 && ch <= 8202) || ch === 8232 || ch === 8233 || ch === 8239 || ch === 8287 || ch === 12288);
},
- safeMeasureText: function (ctx, string) {
- var metric = ctx.measureText(string);
- return metric && metric.width || 0;
+ safeMeasureText: function (ctx, string, desc) {
+ let font = desc || ctx.font;
+ let key = font + "\uD83C\uDFAE" + string;
+ let cache = measureCache.get(key);
+ if (cache !== null) {
+ return cache;
+ }
+
+ let metric = ctx.measureText(string);
+ let width = metric && metric.width || 0;
+ measureCache.put(key, width);
+
+ return width;
+ },
+
+ // in case truncate a character on the Supplementary Multilingual Plane
+ // test case: a = '😉🚗'
+ // _safeSubstring(a, 1) === '😉🚗'
+ // _safeSubstring(a, 0, 1) === '😉'
+ // _safeSubstring(a, 0, 2) === '😉'
+ // _safeSubstring(a, 0, 3) === '😉'
+ // _safeSubstring(a, 0, 4) === '😉🚗'
+ // _safeSubstring(a, 1, 2) === _safeSubstring(a, 1, 3) === '😉'
+ // _safeSubstring(a, 2, 3) === _safeSubstring(a, 2, 4) === '🚗'
+ _safeSubstring (targetString, startIndex, endIndex) {
+ let newStartIndex = startIndex, newEndIndex = endIndex;
+ let startChar = targetString[startIndex];
+ if (this.lowSurrogateRex.test(startChar)) {
+ newStartIndex--;
+ }
+ if (endIndex !== undefined) {
+ if (endIndex - 1 !== startIndex) {
+ let endChar = targetString[endIndex - 1];
+ if (this.highSurrogateRex.test(endChar)) {
+ newEndIndex--;
+ }
+ }
+ else if (this.highSurrogateRex.test(startChar)) {
+ newEndIndex++;
+ }
+ }
+ return targetString.substring(newStartIndex, newEndIndex);
},
fragmentText: function (stringToken, allWidth, maxWidth, measureText) {
@@ -63,7 +217,7 @@ var textUtils = {
while (allWidth > maxWidth && text.length > 1) {
var fuzzyLen = text.length * ( maxWidth / allWidth ) | 0;
- var tmpText = text.substr(fuzzyLen);
+ var tmpText = this._safeSubstring(text, fuzzyLen);
var width = allWidth - measureText(tmpText);
var sLine = tmpText;
var pushNum = 0;
@@ -75,7 +229,7 @@ var textUtils = {
while (width > maxWidth && checkWhile++ < checkCount) {
fuzzyLen *= maxWidth / width;
fuzzyLen = fuzzyLen | 0;
- tmpText = text.substr(fuzzyLen);
+ tmpText = this._safeSubstring(text, fuzzyLen);
width = allWidth - measureText(tmpText);
}
@@ -90,17 +244,22 @@ var textUtils = {
}
fuzzyLen = fuzzyLen + pushNum;
- tmpText = text.substr(fuzzyLen);
+ tmpText = this._safeSubstring(text, fuzzyLen);
width = allWidth - measureText(tmpText);
}
fuzzyLen -= pushNum;
+ // in case maxWidth cannot contain any characters, need at least one character per line
if (fuzzyLen === 0) {
fuzzyLen = 1;
- sLine = sLine.substr(1);
+ sLine = this._safeSubstring(text, 1);
+ }
+ else if (fuzzyLen === 1 && this.highSurrogateRex.test(text[0])) {
+ fuzzyLen = 2;
+ sLine = this._safeSubstring(text, 2);
}
- var sText = text.substr(0, fuzzyLen), result;
+ var sText = this._safeSubstring(text, 0, fuzzyLen), result;
//symbol in the first
if (this.label_wrapinspection) {
@@ -109,8 +268,8 @@ var textUtils = {
fuzzyLen -= result ? result[0].length : 0;
if (fuzzyLen === 0) fuzzyLen = 1;
- sLine = text.substr(fuzzyLen);
- sText = text.substr(0, fuzzyLen);
+ sLine = this._safeSubstring(text, fuzzyLen);
+ sText = this._safeSubstring(text, 0, fuzzyLen);
}
}
@@ -119,8 +278,8 @@ var textUtils = {
result = this.label_lastEnglish.exec(sText);
if (result && sText !== result[0]) {
fuzzyLen -= result[0].length;
- sLine = text.substr(fuzzyLen);
- sText = text.substr(0, fuzzyLen);
+ sLine = this._safeSubstring(text, fuzzyLen);
+ sText = this._safeSubstring(text, 0, fuzzyLen);
}
}
@@ -129,7 +288,7 @@ var textUtils = {
wrappedWords.push(sText);
}
else {
- sText = sText.trim();
+ sText = sText.trimLeft();
if (sText.length > 0) {
wrappedWords.push(sText);
}
@@ -142,7 +301,7 @@ var textUtils = {
wrappedWords.push(text);
}
else {
- text = text.trim();
+ text = text.trimLeft();
if (text.length > 0) {
wrappedWords.push(text);
}
@@ -151,4 +310,4 @@ var textUtils = {
},
};
-module.exports = textUtils;
+cc.textUtils = module.exports = textUtils;
diff --git a/cocos2d/core/utils/texture-util.js b/cocos2d/core/utils/texture-util.js
index a5bd5916cac..a768d672b8e 100644
--- a/cocos2d/core/utils/texture-util.js
+++ b/cocos2d/core/utils/texture-util.js
@@ -2,7 +2,7 @@
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
+ https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
@@ -26,40 +26,28 @@
const Texture2D = require('../assets/CCTexture2D');
-/**
- * cc.textureUtil is a singleton object, it can load cc.Texture2D asynchronously
- * @class textureUtil
- * @static
- */
let textureUtil = {
loadImage (url, cb, target) {
cc.assertID(url, 3103);
- var tex = cc.loader.getRes(url);
+ var tex = cc.assetManager.assets.get(url);
if (tex) {
if (tex.loaded) {
- cb && cb.call(target, tex);
+ cb && cb.call(target, null, tex);
return tex;
}
else
{
tex.once("load", function(){
- cb && cb.call(target, tex);
+ cb && cb.call(target, null, tex);
}, target);
return tex;
}
}
else {
- tex = new Texture2D();
- tex.url = url;
- cc.loader.load({url: url, texture: tex}, function (err, texture) {
- if (err) {
- return cb && cb.call(target, err || new Error('Unknown error'));
- }
- texture.handleLoadedTexture();
- cb && cb.call(target, null, texture);
+ cc.assetManager.loadRemote(url, function (err, texture) {
+ cb && cb.call(target, err, texture);
});
- return tex;
}
},
@@ -67,14 +55,7 @@ let textureUtil = {
if (url && image) {
var tex = new Texture2D();
tex.initWithElement(image);
- var item = {
- id: url,
- url: url, // real download url, maybe changed
- error: null,
- content: tex,
- complete: false
- }
- cc.loader.flowOut(item);
+ cc.assetManager.assets.add(url, tex);
return tex;
}
},
@@ -84,27 +65,16 @@ let textureUtil = {
callback && callback();
return;
}
- if (!texture.url) {
+ if (!texture.nativeUrl) {
callback && callback();
return;
}
// load image
- cc.loader.load({
- url: texture.url,
- // For image, we should skip loader otherwise it will load a new texture
- skips: ['Loader'],
- }, function (err, image) {
- if (image) {
- if (CC_DEBUG && image instanceof cc.Texture2D) {
- return cc.error('internal error: loader handle pipe must be skipped');
- }
- if (!texture.loaded) {
- texture._nativeAsset = image;
- }
- }
+ cc.assetManager.loadNativeFile(texture, function (err, image) {
+ if (!err) texture._nativeAsset = image;
callback && callback(err);
});
}
};
-cc.textureUtil = module.exports = textureUtil;
\ No newline at end of file
+module.exports = textureUtil;
\ No newline at end of file
diff --git a/cocos2d/core/utils/trans-pool/index.js b/cocos2d/core/utils/trans-pool/index.js
new file mode 100644
index 00000000000..dec47e2d48d
--- /dev/null
+++ b/cocos2d/core/utils/trans-pool/index.js
@@ -0,0 +1,31 @@
+/****************************************************************************
+ Copyright (c) 2019 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+let NodeUnit = require('./node-unit');
+let NodeMemPool = require('./node-mem-pool');
+
+module.exports = {
+ NodeMemPool: new NodeMemPool(NodeUnit)
+};
\ No newline at end of file
diff --git a/cocos2d/core/utils/trans-pool/mem-pool.js b/cocos2d/core/utils/trans-pool/mem-pool.js
new file mode 100644
index 00000000000..a73a66ca32c
--- /dev/null
+++ b/cocos2d/core/utils/trans-pool/mem-pool.js
@@ -0,0 +1,109 @@
+/****************************************************************************
+ Copyright (c) 2019 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+let MemPool = function (unitClass) {
+ this._unitClass = unitClass;
+ this._pool = [];
+ this._findOrder = [];
+
+ if (CC_JSB && CC_NATIVERENDERER) {
+ this._initNative();
+ }
+};
+
+let proto = MemPool.prototype;
+proto._initNative = function () {
+ this._nativeMemPool = new renderer.MemPool();
+};
+
+proto._buildUnit = function (unitID) {
+ let unit = new this._unitClass(unitID, this);
+ if (CC_JSB && CC_NATIVERENDERER) {
+ this._nativeMemPool.updateCommonData(unitID, unit._data, unit._signData);
+ }
+ return unit;
+};
+
+proto._destroyUnit = function (unitID) {
+ this._pool[unitID] = null;
+ for (let idx = 0, n = this._findOrder.length; idx < n; idx++) {
+ let unit = this._findOrder[idx];
+ if (unit && unit.unitID == unitID) {
+ this._findOrder.splice(idx, 1);
+ break;
+ }
+ }
+ if (CC_JSB && CC_NATIVERENDERER) {
+ this._nativeMemPool.removeCommonData(unitID);
+ }
+};
+
+proto._findUnitID = function () {
+ let unitID = 0;
+ let pool = this._pool;
+ while (pool[unitID]) unitID++;
+ return unitID;
+};
+
+proto.pop = function () {
+ let findUnit = null;
+ let idx = 0;
+ let findOrder = this._findOrder;
+ let pool = this._pool;
+ for (let n = findOrder.length; idx < n; idx++) {
+ let unit = findOrder[idx];
+ if (unit && unit.hasSpace()) {
+ findUnit = unit;
+ break;
+ }
+ }
+
+ if (!findUnit) {
+ let unitID = this._findUnitID();
+ findUnit = this._buildUnit(unitID);
+ pool[unitID] = findUnit;
+ findOrder.push(findUnit);
+ idx = findOrder.length - 1;
+ }
+
+ // swap has space unit to first position, so next find will fast
+ let firstUnit = findOrder[0];
+ if (firstUnit !== findUnit) {
+ findOrder[0] = findUnit;
+ findOrder[idx] = firstUnit;
+ }
+
+ return findUnit.pop();
+};
+
+proto.push = function (info) {
+ let unit = this._pool[info.unitID];
+ unit.push(info.index);
+ if (this._findOrder.length > 1 && unit.isAllFree()) {
+ this._destroyUnit(info.unitID);
+ }
+ return unit;
+};
+module.exports = MemPool;
\ No newline at end of file
diff --git a/cocos2d/core/utils/trans-pool/node-mem-pool.js b/cocos2d/core/utils/trans-pool/node-mem-pool.js
new file mode 100644
index 00000000000..bedf26d439e
--- /dev/null
+++ b/cocos2d/core/utils/trans-pool/node-mem-pool.js
@@ -0,0 +1,49 @@
+/****************************************************************************
+ Copyright (c) 2019 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+let MemPool = require('./mem-pool');
+let NodeMemPool = function (unitClass) {
+ MemPool.call(this, unitClass);
+};
+
+(function(){
+ let Super = function(){};
+ Super.prototype = MemPool.prototype;
+ NodeMemPool.prototype = new Super();
+})();
+
+let proto = NodeMemPool.prototype;
+proto._initNative = function () {
+ this._nativeMemPool = new renderer.NodeMemPool();
+};
+
+proto._destroyUnit = function (unitID) {
+ MemPool.prototype._destroyUnit.call(this, unitID);
+ if (CC_JSB && CC_NATIVERENDERER) {
+ this._nativeMemPool.removeNodeData(unitID);
+ }
+};
+
+module.exports = NodeMemPool;
\ No newline at end of file
diff --git a/cocos2d/core/utils/trans-pool/node-unit.js b/cocos2d/core/utils/trans-pool/node-unit.js
new file mode 100644
index 00000000000..0a4b6a5bc04
--- /dev/null
+++ b/cocos2d/core/utils/trans-pool/node-unit.js
@@ -0,0 +1,142 @@
+/****************************************************************************
+ Copyright (c) 2019 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import { FLOAT_ARRAY_TYPE, FLOAT_BYTES } from '../../value-types/utils'
+
+const Uint32_Bytes = 4;
+const Uint8_Bytes = 1;
+
+// Space : [Dirty] [Size:4 Uint32]
+const Dirty_Type = Uint32Array;
+const Dirty_Members = 1;
+const Dirty_Stride = Dirty_Members * Uint32_Bytes;
+
+// Space : [TRS] [Size:4 * 10 Float32|Float64]
+const TRS_Members = 10;
+const TRS_Stride = TRS_Members * FLOAT_BYTES;
+
+// Space : [LocalMatrix] [Size:4 * 16 Float32|Float64]
+const LocalMatrix_Members = 16;
+const LocalMatrix_Stride = LocalMatrix_Members * FLOAT_BYTES;
+
+// Space : [WorldMatrix] [Size:4 * 16 Float32|Float64]
+const WorldMatrix_Members = 16;
+const WorldMatrix_Stride = WorldMatrix_Members * FLOAT_BYTES;
+
+// Space : [Parent Unit] [Size:4 Uint32]
+// Space : [Parent Index] [Size:4 Uint32]
+const Parent_Type = Uint32Array;
+const Parent_Members = 2;
+const Parent_Stride = Parent_Members * Uint32_Bytes;
+
+// Space : [ZOrder] [Size:4 Uint32]
+const ZOrder_Type = Uint32Array;
+const ZOrder_Members = 1;
+const ZOrder_Stride = ZOrder_Members * Uint32_Bytes;
+
+// Space : [CullingMask] [Size:4 Int32]
+const CullingMask_Type = Int32Array;
+const CullingMask_Members = 1;
+const CullingMask_Stride = CullingMask_Members * Uint32_Bytes;
+
+// Space : [Opacity] [Size:1 Uint8]
+const Opacity_Type = Uint8Array;
+const Opacity_Members = 1;
+const Opacity_Stride = Opacity_Members * Uint8_Bytes;
+
+// Space : [Is3D] [Size:1 Uint8]
+const Is3D_Type = Uint8Array;
+const Is3D_Members = 1;
+const Is3D_Stride = Is3D_Members * Uint8_Bytes;
+
+// Space : [NodePtr] [Size:4 * 2 Uint32]
+const Node_Type = Uint32Array;
+const Node_Members = 2;
+
+// Space : [Skew] [Size:4 * 2 Float32]
+const Skew_Members = 2;
+const Skew_Stride = Skew_Members * FLOAT_BYTES;
+
+let UnitBase = require('./unit-base');
+let NodeUnit = function (unitID, memPool) {
+ UnitBase.call(this, unitID, memPool);
+
+ let contentNum = this._contentNum;
+ this.trsList = new FLOAT_ARRAY_TYPE(contentNum * TRS_Members);
+ this.localMatList = new FLOAT_ARRAY_TYPE(contentNum * LocalMatrix_Members);
+ this.worldMatList = new FLOAT_ARRAY_TYPE(contentNum * WorldMatrix_Members);
+
+ if (CC_JSB && CC_NATIVERENDERER) {
+ this.dirtyList = new Dirty_Type(contentNum * Dirty_Members);
+ this.parentList = new Parent_Type(contentNum * Parent_Members);
+ this.zOrderList = new ZOrder_Type(contentNum * ZOrder_Members);
+ this.cullingMaskList = new CullingMask_Type(contentNum * CullingMask_Members);
+ this.opacityList = new Opacity_Type(contentNum * Opacity_Members);
+ this.is3DList = new Is3D_Type(contentNum * Is3D_Members);
+ this.nodeList = new Node_Type(contentNum * Node_Members);
+ this.skewList = new FLOAT_ARRAY_TYPE(contentNum * Skew_Members);
+
+ this._memPool._nativeMemPool.updateNodeData(
+ unitID,
+ this.dirtyList,
+ this.trsList,
+ this.localMatList,
+ this.worldMatList,
+ this.parentList,
+ this.zOrderList,
+ this.cullingMaskList,
+ this.opacityList,
+ this.is3DList,
+ this.nodeList,
+ this.skewList
+ );
+ }
+
+ for (let i = 0; i < contentNum; i ++) {
+ let space = this._spacesData[i];
+
+ space.trs = new FLOAT_ARRAY_TYPE(this.trsList.buffer, i * TRS_Stride, TRS_Members);
+ space.localMat = new FLOAT_ARRAY_TYPE(this.localMatList.buffer, i * LocalMatrix_Stride, LocalMatrix_Members);
+ space.worldMat = new FLOAT_ARRAY_TYPE(this.worldMatList.buffer, i * WorldMatrix_Stride, WorldMatrix_Members);
+
+ if (CC_JSB && CC_NATIVERENDERER) {
+ space.dirty = new Dirty_Type(this.dirtyList.buffer, i * Dirty_Stride, Dirty_Members);
+ space.parent = new Parent_Type(this.parentList.buffer, i * Parent_Stride, Parent_Members);
+ space.zOrder = new ZOrder_Type(this.zOrderList.buffer, i * ZOrder_Stride, ZOrder_Members);
+ space.cullingMask = new CullingMask_Type(this.cullingMaskList.buffer, i * CullingMask_Stride, CullingMask_Members);
+ space.opacity = new Opacity_Type(this.opacityList.buffer, i * Opacity_Stride, Opacity_Members);
+ space.is3D = new Is3D_Type(this.is3DList.buffer, i * Is3D_Stride, Is3D_Members);
+ space.skew = new FLOAT_ARRAY_TYPE(this.skewList.buffer, i * Skew_Stride, Skew_Members);
+ }
+ }
+};
+
+(function(){
+ let Super = function(){};
+ Super.prototype = UnitBase.prototype;
+ NodeUnit.prototype = new Super();
+})();
+
+module.exports = NodeUnit;
\ No newline at end of file
diff --git a/cocos2d/core/utils/trans-pool/unit-base.js b/cocos2d/core/utils/trans-pool/unit-base.js
new file mode 100644
index 00000000000..8628a8d7fcf
--- /dev/null
+++ b/cocos2d/core/utils/trans-pool/unit-base.js
@@ -0,0 +1,167 @@
+/****************************************************************************
+ Copyright (c) 2019 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+// Unit has many segment, layout such as :
+// Head Free Pointer + Using Segment Num + Segment 1 + Segment 2 + Segment 3 ...
+
+// sign data format
+// Space : [If Free Flag] [Size:1 Uint16]
+// Space : [Next Free Index] [Size:1 Uint16]
+
+// invalid pointer value
+let POINTER_INVALID_FLAG = 0xffff;
+let SPACE_FREE_FLAG = 0x0;
+let SPACE_USE_FLAG = 0x1;
+let POS_NEXT_FREE = 0;
+let POS_FREE_FLAG = 1;
+
+let UnitBase = function (unitID, memPool, contentNum) {
+ contentNum = contentNum || 128;
+
+ // set unit id
+ this.unitID = unitID;
+ this._memPool = memPool;
+
+ this._data = new Uint16Array(2);
+ // head of the free content index
+ this._data[0] = 0;
+ // using segment num
+ this._data[1] = 0;
+
+ this._contentNum = contentNum;
+ this._signData = new Uint16Array(this._contentNum * 2);
+ this._spacesData = [];
+
+ for (let i = 0; i < contentNum; i++) {
+ let signIndex = i * 2;
+ // store content block index but not sign array index
+ this._signData[signIndex + POS_NEXT_FREE] = i + 1;
+ this._signData[signIndex + POS_FREE_FLAG] = SPACE_FREE_FLAG;
+
+ this._spacesData[i] = {
+ index: i,
+ unitID: unitID,
+ };
+ }
+ // last one has no next space;
+ this._signData[(contentNum - 1) * 2] = POINTER_INVALID_FLAG;
+};
+
+let UnitBaseProto = UnitBase.prototype;
+UnitBaseProto.hasSpace = function () {
+ return this._data[0] !== POINTER_INVALID_FLAG;
+};
+
+UnitBaseProto.isAllFree = function () {
+ return this._data[1] == 0;
+};
+
+// pop space from unit
+UnitBaseProto.pop = function () {
+ let headFreeIndex = this._data[0];
+ if (headFreeIndex === POINTER_INVALID_FLAG) return null;
+
+ let index = headFreeIndex;
+ let signIndex = index * 2;
+ let space = this._spacesData[index];
+
+ // set use flag
+ this._signData[signIndex + POS_FREE_FLAG] = SPACE_USE_FLAG;
+
+ // store new next free space index
+ this._data[0] = this._signData[signIndex + POS_NEXT_FREE];
+ // add using segment num
+ this._data[1]++;
+ return space;
+};
+
+// push back to unit
+UnitBaseProto.push = function (index) {
+ let signIndex = index * 2;
+
+ // set free flag
+ this._signData[signIndex + POS_FREE_FLAG] = SPACE_FREE_FLAG;
+
+ // store head free index to the space
+ this._signData[signIndex + POS_NEXT_FREE] = this._data[0];
+ // update head free index
+ this._data[0] = index;
+ // sub using segment num
+ this._data[1]--;
+};
+
+// dump all space info
+UnitBaseProto.dump = function () {
+ let spaceNum = 0;
+ let index = this._data[0];
+ let freeStr = "";
+
+ while (index != POINTER_INVALID_FLAG) {
+ spaceNum ++;
+ freeStr += index + "->";
+ index = this._signData[index * 2 + POS_NEXT_FREE];
+ }
+
+ let usingNum = 0;
+ let usingStr = "";
+ let contentNum = this._contentNum;
+ for (let i = 0; i < contentNum; i++) {
+ let freeFlag = this._signData[i * 2 + POS_FREE_FLAG];
+ if (freeFlag == SPACE_USE_FLAG) {
+ usingNum ++;
+ usingStr += i + "->";
+ }
+ }
+
+ let totalNum = spaceNum + usingNum;
+ console.log(
+ "unitID:", this.unitID,
+ "spaceNum:", spaceNum,
+ "calc using num:", usingNum,
+ 'store using num:', this._data[1],
+ 'calc total num:', totalNum,
+ 'actually total num:', this._contentNum
+ );
+ console.log("free info:", freeStr);
+ console.log("using info:", usingStr);
+
+ if (usingNum != this._data[1]) {
+ cc.error(
+ 'using num error',
+ "calc using num:", usingNum,
+ 'store using num:', this._data[1]
+ );
+ }
+
+ if (spaceNum + usingNum != this._contentNum) {
+ cc.error(
+ 'total num error',
+ 'calc total num:', totalNum,
+ 'actually total num:', this._contentNum
+ );
+ }
+};
+
+module.exports = UnitBase;
\ No newline at end of file
diff --git a/cocos2d/core/value-types/color.js b/cocos2d/core/value-types/color.js
deleted file mode 100644
index 5375baf18e1..00000000000
--- a/cocos2d/core/value-types/color.js
+++ /dev/null
@@ -1,613 +0,0 @@
-/****************************************************************************
- Copyright (c) 2013-2016 Chukong Technologies Inc.
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos.com
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
-
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
-
-var ValueType = require('./value-type');
-var js = require('../platform/js');
-
-var Color = (function () {
-
- /**
- * !#en
- * Representation of RGBA colors.
- *
- * Each color component is a floating point value with a range from 0 to 255.
- *
- * You can also use the convenience method {{#crossLink "cc/color:method"}}cc.color{{/crossLink}} to create a new Color.
- *
- * !#zh
- * cc.Color 用于表示颜色。
- *
- * 它包含 RGBA 四个以浮点数保存的颜色分量,每个的值都在 0 到 255 之间。
- *
- * 您也可以通过使用 {{#crossLink "cc/color:method"}}cc.color{{/crossLink}} 的便捷方法来创建一个新的 Color。
- *
- * @class Color
- * @extends ValueType
- */
- /**
- * @method constructor
- * @param {Number} [r=0] - red component of the color, default value is 0.
- * @param {Number} [g=0] - green component of the color, defualt value is 0.
- * @param {Number} [b=0] - blue component of the color, default value is 0.
- * @param {Number} [a=255] - alpha component of the color, default value is 255.
- */
- function Color( r, g, b, a ) {
- if (typeof r === 'object') {
- g = r.g;
- b = r.b;
- a = r.a;
- r = r.r;
- }
- r = r || 0;
- g = g || 0;
- b = b || 0;
- a = typeof a === 'number' ? a : 255;
- this._val = ((a<<24) >>> 0) + (b<<16) + (g<<8) + r;
- }
- js.extend(Color, ValueType);
- require('../platform/CCClass').fastDefine('cc.Color', Color, {r: 0, g: 0, b: 0, a: 255});
-
- var DefaultColors = {
- // color: [r, g, b, a]
- /**
- * !#en Solid white, RGBA is [255, 255, 255, 255].
- * !#zh 纯白色,RGBA 是 [255, 255, 255, 255]。
- * @property WHITE
- * @type {Color}
- * @static
- */
- WHITE: [255, 255, 255, 255],
- /**
- * !#en Solid black, RGBA is [0, 0, 0, 255].
- * !#zh 纯黑色,RGBA 是 [0, 0, 0, 255]。
- * @property BLACK
- * @type {Color}
- * @static
- */
- BLACK: [0, 0, 0, 255],
- /**
- * !#en Transparent, RGBA is [0, 0, 0, 0].
- * !#zh 透明,RGBA 是 [0, 0, 0, 0]。
- * @property TRANSPARENT
- * @type {Color}
- * @static
- */
- TRANSPARENT:[0, 0, 0, 0],
- /**
- * !#en Grey, RGBA is [127.5, 127.5, 127.5].
- * !#zh 灰色,RGBA 是 [127.5, 127.5, 127.5]。
- * @property GRAY
- * @type {Color}
- * @static
- */
- GRAY: [127.5, 127.5, 127.5],
- /**
- * !#en Solid red, RGBA is [255, 0, 0].
- * !#zh 纯红色,RGBA 是 [255, 0, 0]。
- * @property RED
- * @type {Color}
- * @static
- */
- RED: [255, 0, 0],
- /**
- * !#en Solid green, RGBA is [0, 255, 0].
- * !#zh 纯绿色,RGBA 是 [0, 255, 0]。
- * @property GREEN
- * @type {Color}
- * @static
- */
- GREEN: [0, 255, 0],
- /**
- * !#en Solid blue, RGBA is [0, 0, 255].
- * !#zh 纯蓝色,RGBA 是 [0, 0, 255]。
- * @property BLUE
- * @type {Color}
- * @static
- */
- BLUE: [0, 0, 255],
- /**
- * !#en Yellow, RGBA is [255, 235, 4].
- * !#zh 黄色,RGBA 是 [255, 235, 4]。
- * @property YELLOW
- * @type {Color}
- * @static
- */
- YELLOW: [255, 235, 4],
- /**
- * !#en Orange, RGBA is [255, 127, 0].
- * !#zh 橙色,RGBA 是 [255, 127, 0]。
- * @property ORANGE
- * @type {Color}
- * @static
- */
- ORANGE: [255, 127, 0],
- /**
- * !#en Cyan, RGBA is [0, 255, 255].
- * !#zh 青色,RGBA 是 [0, 255, 255]。
- * @property CYAN
- * @type {Color}
- * @static
- */
- CYAN: [0, 255, 255],
- /**
- * !#en Magenta, RGBA is [255, 0, 255].
- * !#zh 洋红色(品红色),RGBA 是 [255, 0, 255]。
- * @property MAGENTA
- * @type {Color}
- * @static
- */
- MAGENTA: [255, 0, 255]
- };
- for (var colorName in DefaultColors) {
- js.get(Color, colorName, (function (rgba) {
- return function () {
- return new Color(rgba[0], rgba[1], rgba[2], rgba[3]);
- };
- })(DefaultColors[colorName]));
- }
-
- var proto = Color.prototype;
-
- /**
- * !#en Clone a new color from the current color.
- * !#zh 克隆当前颜色。
- * @method clone
- * @return {Color} Newly created color.
- * @example
- * var color = new cc.Color();
- * var newColor = color.clone();// Color {r: 0, g: 0, b: 0, a: 255}
- */
- proto.clone = function () {
- var ret = new Color();
- ret._val = this._val;
- return ret;
- };
-
- /**
- * !#en TODO
- * !#zh 判断两个颜色是否相等。
- * @method equals
- * @param {Color} other
- * @return {Boolean}
- * @example
- * var color1 = cc.Color.WHITE;
- * var color2 = new cc.Color(255, 255, 255);
- * cc.log(color1.equals(color2)); // true;
- * color2 = cc.Color.RED;
- * cc.log(color2.equals(color1)); // false;
- */
- proto.equals = function (other) {
- return other && this._val === other._val;
- };
-
- /**
- * !#en TODO
- * !#zh 线性插值
- * @method lerp
- * @param {Color} to
- * @param {number} ratio - the interpolation coefficient.
- * @param {Color} [out] - optional, the receiving vector.
- * @return {Color}
- * @example {@link utils/api/engine/docs/cocos2d/core/value-types/CCColor/lerp.js}
- */
- proto.lerp = function (to, ratio, out) {
- out = out || new Color();
- var r = this.r;
- var g = this.g;
- var b = this.b;
- var a = this.a;
- out.r = r + (to.r - r) * ratio;
- out.g = g + (to.g - g) * ratio;
- out.b = b + (to.b - b) * ratio;
- out.a = a + (to.a - a) * ratio;
- return out;
- };
-
- /**
- * !#en TODO
- * !#zh 转换为方便阅读的字符串。
- * @method toString
- * @return {String}
- * @example
- * var color = cc.Color.WHITE;
- * color.toString(); // "rgba(255, 255, 255, 255)"
- */
- proto.toString = function () {
- return "rgba(" +
- this.r.toFixed() + ", " +
- this.g.toFixed() + ", " +
- this.b.toFixed() + ", " +
- this.a.toFixed() + ")";
- };
-
- /**
- * !#en Gets red channel value
- * !#zh 获取当前颜色的红色值。
- * @method getR
- * @return {Number} red value.
- */
- proto.getR = function () {
- return this._val & 0x000000ff;
- };
- /**
- * !#en Sets red value and return the current color object
- * !#zh 设置当前的红色值,并返回当前对象。
- * @method setR
- * @param {Number} red - the new Red component.
- * @return {Color} this color.
- * @example
- * var color = new cc.Color();
- * color.setR(255); // Color {r: 255, g: 0, b: 0, a: 255}
- */
- proto.setR = function (red) {
- red = ~~cc.misc.clampf(red, 0, 255);
- this._val = ((this._val & 0xffffff00) | red) >>> 0;
- return this;
- };
- /**
- * !#en Gets green channel value
- * !#zh 获取当前颜色的绿色值。
- * @method getG
- * @return {Number} green value.
- */
- proto.getG = function () {
- return (this._val & 0x0000ff00) >> 8;
- };
- /**
- * !#en Sets green value and return the current color object
- * !#zh 设置当前的绿色值,并返回当前对象。
- * @method setG
- * @param {Number} green - the new Green component.
- * @return {Color} this color.
- * @example
- * var color = new cc.Color();
- * color.setG(255); // Color {r: 0, g: 255, b: 0, a: 255}
- */
- proto.setG = function (green) {
- green = ~~cc.misc.clampf(green, 0, 255);
- this._val = ((this._val & 0xffff00ff) | (green << 8)) >>> 0;
- return this;
- };
- /**
- * !#en Gets blue channel value
- * !#zh 获取当前颜色的蓝色值。
- * @method getB
- * @return {Number} blue value.
- */
- proto.getB = function () {
- return (this._val & 0x00ff0000) >> 16;
- };
- /**
- * !#en Sets blue value and return the current color object
- * !#zh 设置当前的蓝色值,并返回当前对象。
- * @method setB
- * @param {Number} blue - the new Blue component.
- * @return {Color} this color.
- * @example
- * var color = new cc.Color();
- * color.setB(255); // Color {r: 0, g: 0, b: 255, a: 255}
- */
- proto.setB = function (blue) {
- blue = ~~cc.misc.clampf(blue, 0, 255);
- this._val = ((this._val & 0xff00ffff) | (blue << 16)) >>> 0;
- return this;
- };
- /**
- * !#en Gets alpha channel value
- * !#zh 获取当前颜色的透明度值。
- * @method getA
- * @return {Number} alpha value.
- */
- proto.getA = function () {
- return (this._val & 0xff000000) >>> 24;
- };
- /**
- * !#en Sets alpha value and return the current color object
- * !#zh 设置当前的透明度,并返回当前对象。
- * @method setA
- * @param {Number} alpha - the new Alpha component.
- * @return {Color} this color.
- * @example
- * var color = new cc.Color();
- * color.setA(0); // Color {r: 0, g: 0, b: 0, a: 0}
- */
- proto.setA = function (alpha) {
- alpha = ~~cc.misc.clampf(alpha, 0, 255);
- this._val = ((this._val & 0x00ffffff) | ((alpha << 24) >>> 0)) >>> 0;
- return this;
- };
-
- js.getset(proto, 'r', proto.getR, proto.setR, true);
- js.getset(proto, 'g', proto.getG, proto.setG, true);
- js.getset(proto, 'b', proto.getB, proto.setB, true);
- js.getset(proto, 'a', proto.getA, proto.setA, true);
-
- /**
- * !#en Convert color to css format.
- * !#zh 转换为 CSS 格式。
- * @method toCSS
- * @param {String} opt - "rgba", "rgb", "#rgb" or "#rrggbb".
- * @return {String}
- * @example {@link utils/api/engine/docs/cocos2d/core/value-types/CCColor/toCSS.js}
- */
- proto.toCSS = function ( opt ) {
- if ( opt === 'rgba' ) {
- return "rgba(" +
- (this.r | 0 ) + "," +
- (this.g | 0 ) + "," +
- (this.b | 0 ) + "," +
- (this.a / 255).toFixed(2) + ")"
- ;
- }
- else if ( opt === 'rgb' ) {
- return "rgb(" +
- (this.r | 0 ) + "," +
- (this.g | 0 ) + "," +
- (this.b | 0 ) + ")"
- ;
- }
- else {
- return '#' + this.toHEX(opt);
- }
- };
-
- /**
- * !#en Read hex string and store color data into the current color object, the hex string must be formated as rgba or rgb.
- * !#zh 读取 16 进制颜色。
- * @method fromHEX
- * @param {String} hexString
- * @return {Color}
- * @chainable
- * @example
- * var color = cc.Color.BLACK;
- * color.fromHEX("#FFFF33"); // Color {r: 255, g: 255, b: 51, a: 255};
- */
- proto.fromHEX = function (hexString) {
- hexString = (hexString.indexOf('#') === 0) ? hexString.substring(1) : hexString;
- let r = parseInt(hexString.substr(0, 2), 16) || 0;
- let g = parseInt(hexString.substr(2, 2), 16) || 0;
- let b = parseInt(hexString.substr(4, 2), 16) || 0;
- let a = parseInt(hexString.substr(6, 2), 16) || 255;
- this._val = ((a<<24) >>> 0) + (b<<16) + (g<<8) + r;
- return this;
- };
-
- /**
- * !#en convert Color to HEX color string.
- * e.g. cc.color(255,6,255) to : "#ff06ff"
- * !#zh 转换为 16 进制。
- * @method toHEX
- * @param {String} fmt - "#rgb", "#rrggbb" or "#rrggbbaa".
- * @return {String}
- * @example
- * var color = cc.Color.BLACK;
- * color.toHEX("#rgb"); // "000";
- * color.toHEX("#rrggbb"); // "000000";
- */
- proto.toHEX = function ( fmt ) {
- var hex = [
- (this.r | 0 ).toString(16),
- (this.g | 0 ).toString(16),
- (this.b | 0 ).toString(16)
- ];
- var i = -1;
- if ( fmt === '#rgb' ) {
- for ( i = 0; i < hex.length; ++i ) {
- if ( hex[i].length > 1 ) {
- hex[i] = hex[i][0];
- }
- }
- }
- else if ( fmt === '#rrggbb' ) {
- for ( i = 0; i < hex.length; ++i ) {
- if ( hex[i].length === 1 ) {
- hex[i] = '0' + hex[i];
- }
- }
- }
- else if ( fmt === '#rrggbbaa' ) {
- hex.push((this.a | 0 ).toString(16));
- for ( i = 0; i < hex.length; ++i ) {
- if ( hex[i].length === 1 ) {
- hex[i] = '0' + hex[i];
- }
- }
- }
- return hex.join('');
- };
-
- /**
- * !#en Convert to 24bit rgb value.
- * !#zh 转换为 24bit 的 RGB 值。
- * @method toRGBValue
- * @return {Number}
- * @example
- * var color = cc.Color.YELLOW;
- * color.toRGBValue(); // 16771844;
- */
- proto.toRGBValue = function () {
- return this._val & 0x00ffffff;
- };
-
- /**
- * !#en Read HSV model color and convert to RGB color
- * !#zh 读取 HSV(色彩模型)格式。
- * @method fromHSV
- * @param {Number} h
- * @param {Number} s
- * @param {Number} v
- * @return {Color}
- * @chainable
- * @example
- * var color = cc.Color.YELLOW;
- * color.fromHSV(0, 0, 1); // Color {r: 255, g: 255, b: 255, a: 255};
- */
- proto.fromHSV = function ( h, s, v ) {
- var r, g, b;
- if (s === 0) {
- r = g = b = v;
- }
- else {
- if (v === 0) {
- r = g = b = 0;
- }
- else {
- if (h === 1) h = 0;
- h *= 6;
- s = s;
- v = v;
- var i = Math.floor(h);
- var f = h - i;
- var p = v * (1 - s);
- var q = v * (1 - (s * f));
- var t = v * (1 - (s * (1 - f)));
- switch (i) {
- case 0:
- r = v;
- g = t;
- b = p;
- break;
-
- case 1:
- r = q;
- g = v;
- b = p;
- break;
-
- case 2:
- r = p;
- g = v;
- b = t;
- break;
-
- case 3:
- r = p;
- g = q;
- b = v;
- break;
-
- case 4:
- r = t;
- g = p;
- b = v;
- break;
-
- case 5:
- r = v;
- g = p;
- b = q;
- break;
- }
- }
- }
- r *= 255;
- g *= 255;
- b *= 255;
- this._val = ((this.a<<24) >>> 0) + (b<<16) + (g<<8) + r;
- return this;
- };
-
- /**
- * !#en Transform to HSV model color
- * !#zh 转换为 HSV(色彩模型)格式。
- * @method toHSV
- * @return {Object} - {h: number, s: number, v: number}.
- * @example
- * var color = cc.Color.YELLOW;
- * color.toHSV(); // Object {h: 0.1533864541832669, s: 0.9843137254901961, v: 1};
- */
- proto.toHSV = function () {
- var r = this.r / 255;
- var g = this.g / 255;
- var b = this.b / 255;
- var hsv = { h: 0, s: 0, v: 0 };
- var max = Math.max(r,g,b);
- var min = Math.min(r,g,b);
- var delta = 0;
- hsv.v = max;
- hsv.s = max ? (max - min) / max : 0;
- if (!hsv.s) hsv.h = 0;
- else {
- delta = max - min;
- if (r === max) hsv.h = (g - b) / delta;
- else if (g === max) hsv.h = 2 + (b - r) / delta;
- else hsv.h = 4 + (r - g) / delta;
- hsv.h /= 6;
- if (hsv.h < 0) hsv.h += 1.0;
- }
- return hsv;
- };
-
- proto.set = function (color) {
- if (color._val) {
- this._val = color._val;
- }
- else {
- this.r = color.r;
- this.g = color.g;
- this.b = color.b;
- this.a = color.a;
- }
- };
-
- return Color;
-})();
-
-cc.Color = Color;
-
-/**
- * @module cc
- */
-
-/**
- * !#en
- * The convenience method to create a new {{#crossLink "Color/Color:method"}}cc.Color{{/crossLink}}
- * Alpha channel is optional. Default value is 255.
- *
- * !#zh
- * 通过该方法来创建一个新的 {{#crossLink "Color/Color:method"}}cc.Color{{/crossLink}} 对象。
- * Alpha 通道是可选的。默认值是 255。
- *
- * @method color
- * @param {Number} [r=0]
- * @param {Number} [g=0]
- * @param {Number} [b=0]
- * @param {Number} [a=255]
- * @return {Color}
- * @example {@link utils/api/engine/docs/cocos2d/core/value-types/CCColor/color.js}
- */
-cc.color = function color (r, g, b, a) {
- if (typeof r === 'string') {
- var result = new cc.Color();
- return result.fromHEX(r);
- }
- if (typeof r === 'object') {
- return new cc.Color(r.r, r.g, r.b, r.a);
- }
- return new cc.Color(r, g, b, a);
-};
-
-module.exports = cc.Color;
\ No newline at end of file
diff --git a/cocos2d/core/value-types/color.ts b/cocos2d/core/value-types/color.ts
new file mode 100644
index 00000000000..98145376451
--- /dev/null
+++ b/cocos2d/core/value-types/color.ts
@@ -0,0 +1,908 @@
+/****************************************************************************
+ Copyright (c) 2013-2016 Chukong Technologies Inc.
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+import ValueType from './value-type';
+import CCClass from '../platform/CCClass';
+import misc from '../utils/misc';
+
+/**
+ * !#en
+ * Representation of RGBA colors.
+ *
+ * Each color component is a floating point value with a range from 0 to 255.
+ *
+ * You can also use the convenience method {{#crossLink "cc/color:method"}}cc.color{{/crossLink}} to create a new Color.
+ *
+ * !#zh
+ * cc.Color 用于表示颜色。
+ *
+ * 它包含 RGBA 四个以浮点数保存的颜色分量,每个的值都在 0 到 255 之间。
+ *
+ * 您也可以通过使用 {{#crossLink "cc/color:method"}}cc.color{{/crossLink}} 的便捷方法来创建一个新的 Color。
+ *
+ * @class Color
+ * @extends ValueType
+ */
+export default class Color extends ValueType {
+ static div = Color.divide;
+ static sub = Color.subtract;
+ static mul = Color.multiply;
+
+ /**
+ * !#en Solid white, RGBA is [255, 255, 255, 255].
+ * !#zh 纯白色,RGBA 是 [255, 255, 255, 255]。
+ * @property WHITE
+ * @type {Color}
+ * @static
+ */
+ static get WHITE () { return new Color(255, 255, 255, 255); }
+ static readonly WHITE_R: Color = Color.WHITE;
+
+ /**
+ * !#en Solid black, RGBA is [0, 0, 0, 255].
+ * !#zh 纯黑色,RGBA 是 [0, 0, 0, 255]。
+ * @property BLACK
+ * @type {Color}
+ * @static
+ */
+ static get BLACK () { return new Color(0, 0, 0, 255); }
+ static readonly BLACK_R: Color = Color.BLACK;
+
+ /**
+ * !#en Transparent, RGBA is [0, 0, 0, 0].
+ * !#zh 透明,RGBA 是 [0, 0, 0, 0]。
+ * @property TRANSPARENT
+ * @type {Color}
+ * @static
+ */
+ static get TRANSPARENT () { return new Color(0, 0, 0, 0); }
+ static readonly TRANSPARENT_R: Color = Color.TRANSPARENT;
+
+ /**
+ * !#en Grey, RGBA is [127.5, 127.5, 127.5].
+ * !#zh 灰色,RGBA 是 [127.5, 127.5, 127.5]。
+ * @property GRAY
+ * @type {Color}
+ * @static
+ */
+ static get GRAY () { return new Color(127.5, 127.5, 127.5); }
+ static readonly GRAY_R: Color = Color.GRAY;
+
+ /**
+ * !#en Solid red, RGBA is [255, 0, 0].
+ * !#zh 纯红色,RGBA 是 [255, 0, 0]。
+ * @property RED
+ * @type {Color}
+ * @static
+ */
+ static get RED () { return new Color(255, 0, 0); }
+ static readonly RED_R: Color = Color.RED;
+ /**
+ * !#en Solid green, RGBA is [0, 255, 0].
+ * !#zh 纯绿色,RGBA 是 [0, 255, 0]。
+ * @property GREEN
+ * @type {Color}
+ * @static
+ */
+ static get GREEN () { return new Color(0, 255, 0); }
+ static readonly GREEN_R: Color = Color.GREEN;
+ /**
+ * !#en Solid blue, RGBA is [0, 0, 255].
+ * !#zh 纯蓝色,RGBA 是 [0, 0, 255]。
+ * @property BLUE
+ * @type {Color}
+ * @static
+ */
+ static get BLUE () { return new Color(0, 0, 255); }
+ static readonly BLUE_R: Color = Color.BLUE;
+ /**
+ * !#en Yellow, RGBA is [255, 235, 4].
+ * !#zh 黄色,RGBA 是 [255, 235, 4]。
+ * @property YELLOW
+ * @type {Color}
+ * @static
+ */
+ static get YELLOW () { return new Color(255, 235, 4); }
+ static readonly YELLOW_R: Color = Color.YELLOW;
+ /**
+ * !#en Orange, RGBA is [255, 127, 0].
+ * !#zh 橙色,RGBA 是 [255, 127, 0]。
+ * @property ORANGE
+ * @type {Color}
+ * @static
+ */
+ static get ORANGE () { return new Color(255, 127, 0); }
+ static readonly ORANGE_R: Color = Color.ORANGE;
+ /**
+ * !#en Cyan, RGBA is [0, 255, 255].
+ * !#zh 青色,RGBA 是 [0, 255, 255]。
+ * @property CYAN
+ * @type {Color}
+ * @static
+ */
+ static get CYAN () { return new Color(0, 255, 255); }
+ static readonly CYAN_R: Color = Color.CYAN;
+ /**
+ * !#en Magenta, RGBA is [255, 0, 255].
+ * !#zh 洋红色(品红色),RGBA 是 [255, 0, 255]。
+ * @property MAGENTA
+ * @type {Color}
+ * @static
+ */
+ static get MAGENTA () { return new Color(255, 0, 255); }
+ static readonly MAGENTA_R: Color = Color.MAGENTA;
+
+ /**
+ * Copy content of a color into another.
+ * @method copy
+ * @typescript
+ * copy (out: Color, a: Color): Color
+ * @static
+ */
+ static copy (out: Color, a: Color): Color {
+ out.r = a.r;
+ out.g = a.g;
+ out.b = a.b;
+ out.a = a.a;
+ return out;
+ }
+
+ /**
+ * Clone a new color.
+ * @method clone
+ * @typescript
+ * clone (a: Color): Color
+ * @static
+ */
+ static clone (a: Color): Color {
+ return new Color(a.r, a.g, a.b, a.a);
+ }
+
+ /**
+ * Set the components of a color to the given values.
+ * @method set
+ * @typescript
+ * set (out: Color, r?: number, g?: number, b?: number, a?: number): Color
+ * @static
+ */
+ static set (out: Color, r = 255, g = 255, b = 255, a = 255): Color {
+ out.r = r;
+ out.g = g;
+ out.b = b;
+ out.a = a;
+ return out;
+ }
+
+ /**
+ * Converts the hexadecimal formal color into rgb formal.
+ * @method fromHex
+ * @typescript
+ * fromHex (out: Color, hex: number): Color
+ * @static
+ * @deprecated
+ */
+ static fromHex (out: Color, hex: number): Color {
+ let r = ((hex >> 24)) / 255.0;
+ let g = ((hex >> 16) & 0xff) / 255.0;
+ let b = ((hex >> 8) & 0xff) / 255.0;
+ let a = ((hex) & 0xff) / 255.0;
+
+ out.r = r;
+ out.g = g;
+ out.b = b;
+ out.a = a;
+ return out;
+ }
+
+ /**
+ * Converts the hexadecimal formal color into rgb formal.
+ * @method fromHEX
+ * @typescript
+ * fromHEX (out: Color, hex: string): Color
+ * @static
+ */
+ static fromHEX (out: Color, hexString: string): Color {
+ hexString = (hexString.indexOf('#') === 0) ? hexString.substring(1) : hexString;
+ out.r = parseInt(hexString.substr(0, 2), 16) || 0;
+ out.g = parseInt(hexString.substr(2, 2), 16) || 0;
+ out.b = parseInt(hexString.substr(4, 2), 16) || 0;
+ out.a = parseInt(hexString.substr(6, 2), 16) || 255;
+ out._val = ((out.a << 24) >>> 0) + (out.b << 16) + (out.g << 8) + out.r;
+ return out;
+ }
+
+ /**
+ * Add components of two colors, respectively.
+ * @method add
+ * @typescript
+ * add (out: Color, a: Color, b: Color): Color
+ * @static
+ */
+ static add (out: Color, a: Color, b: Color): Color {
+ out.r = a.r + b.r;
+ out.g = a.g + b.g;
+ out.b = a.b + b.b;
+ out.a = a.a + b.a;
+ return out;
+ }
+
+ /**
+ * Subtract components of color b from components of color a, respectively.
+ * @method subtract
+ * @typescript
+ * subtract (out: Color, a: Color, b: Color): Color
+ * @static
+ */
+ static subtract (out: Color, a: Color, b: Color): Color {
+ out.r = a.r - b.r;
+ out.g = a.g - b.g;
+ out.b = a.b - b.b;
+ out.a = a.a - b.a;
+ return out;
+ }
+
+ /**
+ * Multiply components of two colors, respectively.
+ * @method multiply
+ * @typescript
+ * multiply (out: Color, a: Color, b: Color): Color
+ * @static
+ */
+ static multiply (out: Color, a: Color, b: Color): Color {
+ out.r = a.r * b.r;
+ out.g = a.g * b.g;
+ out.b = a.b * b.b;
+ out.a = a.a * b.a;
+ return out;
+ }
+
+ /**
+ * Divide components of color a by components of color b, respectively.
+ * @method divide
+ * @typescript
+ * divide (out: Color, a: Color, b: Color): Color
+ * @static
+ */
+ static divide (out: Color, a: Color, b: Color): Color {
+ out.r = a.r / b.r;
+ out.g = a.g / b.g;
+ out.b = a.b / b.b;
+ out.a = a.a / b.a;
+ return out;
+ }
+
+ /**
+ * Scales a color by a number.
+ * @method scale
+ * @typescript
+ * scale (out: Color, a: Color, b: number): Color
+ * @static
+ */
+ static scale (out: Color, a: Color, b: number): Color {
+ out.r = a.r * b;
+ out.g = a.g * b;
+ out.b = a.b * b;
+ out.a = a.a * b;
+ return out;
+ }
+
+ /**
+ * Performs a linear interpolation between two colors.
+ * @method lerp
+ * @typescript
+ * lerp (out: Color, a: Color, b: Color, t: number): Color
+ * @static
+ */
+ static lerp (out: Color, a: Color, b: Color, t: number): Color {
+ let ar = a.r,
+ ag = a.g,
+ ab = a.b,
+ aa = a.a;
+ out.r = ar + t * (b.r - ar);
+ out.g = ag + t * (b.g - ag);
+ out.b = ab + t * (b.b - ab);
+ out.a = aa + t * (b.a - aa);
+ return out;
+ }
+
+ /**
+ * !#zh 颜色转数组
+ * !#en Turn an array of colors
+ * @method toArray
+ * @typescript
+ * toArray > (out: Out, a: IColorLike, ofs?: number): Out
+ * @param ofs 数组起始偏移量
+ * @static
+ */
+ static toArray> (out: Out, a: IColorLike, ofs = 0) {
+ const scale = (a instanceof Color || a.a > 1) ? 1 / 255 : 1;
+ out[ofs + 0] = a.r * scale;
+ out[ofs + 1] = a.g * scale;
+ out[ofs + 2] = a.b * scale;
+ out[ofs + 3] = a.a * scale;
+ return out;
+ }
+
+ /**
+ * !#zh 数组转颜色
+ * !#en An array of colors turn
+ * @method fromArray
+ * @typescript
+ * fromArray (arr: IWritableArrayLike, out: Out, ofs?: number): Out
+ * @param ofs 数组起始偏移量
+ * @static
+ */
+ static fromArray (arr: IWritableArrayLike, out: Out, ofs = 0) {
+ out.r = arr[ofs + 0] * 255;
+ out.g = arr[ofs + 1] * 255;
+ out.b = arr[ofs + 2] * 255;
+ out.a = arr[ofs + 3] * 255;
+ return out;
+ }
+
+ /**
+ * !#zh 颜色 RGB 预乘 Alpha 通道
+ * !#en RGB premultiply alpha channel
+ * @method premultiplyAlpha
+ * @typescript
+ * premultiplyAlpha (out: Out, a: IColorLike)
+ * @param out 返回颜色
+ * @param color 预乘处理的目标颜色
+ * @static
+ */
+ static premultiplyAlpha (out, color) {
+ let alpha = color.a / 255.0;
+ out.r = color.r * alpha;
+ out.g = color.g * alpha;
+ out.b = color.b * alpha;
+
+ out._fastSetA(color.a);
+
+ return out;
+ }
+
+ _val: number = 0;
+
+ /**
+ * @method constructor
+ * @param {Number} [r=0] - red component of the color, default value is 0.
+ * @param {Number} [g=0] - green component of the color, defualt value is 0.
+ * @param {Number} [b=0] - blue component of the color, default value is 0.
+ * @param {Number} [a=255] - alpha component of the color, default value is 255.
+ */
+ constructor (r: Color | number = 0, g: number = 0, b: number = 0, a: number = 255) {
+ super();
+ if (typeof r === 'object') {
+ g = r.g;
+ b = r.b;
+ a = r.a;
+ r = r.r;
+ }
+
+ this._val = ((a << 24) >>> 0) + (b << 16) + (g << 8) + (r|0);
+ }
+
+ /**
+ * !#en Clone a new color from the current color.
+ * !#zh 克隆当前颜色。
+ * @method clone
+ * @return {Color} Newly created color.
+ * @example
+ * var color = new cc.Color();
+ * var newColor = color.clone();// Color {r: 0, g: 0, b: 0, a: 255}
+ */
+ clone (): Color {
+ var ret = new Color();
+ ret._val = this._val;
+ return ret;
+ }
+
+ /**
+ * !#en TODO
+ * !#zh 判断两个颜色是否相等。
+ * @method equals
+ * @param {Color} other
+ * @return {Boolean}
+ * @example
+ * var color1 = cc.Color.WHITE;
+ * var color2 = new cc.Color(255, 255, 255);
+ * cc.log(color1.equals(color2)); // true;
+ * color2 = cc.Color.RED;
+ * cc.log(color2.equals(color1)); // false;
+ */
+ equals (other: Color): boolean {
+ return other && this._val === other._val;
+ }
+
+ /**
+ * !#en TODO
+ * !#zh 线性插值
+ * @method lerp
+ * @param {Color} to
+ * @param {number} ratio - the interpolation coefficient.
+ * @param {Color} [out] - optional, the receiving vector.
+ * @return {Color}
+ * @example {@link cocos2d/core/value-types/CCColor/lerp.js}
+ */
+ lerp (to: Color, ratio: number, out?: Color): Color {
+ out = out || new Color();
+ var r = this.r;
+ var g = this.g;
+ var b = this.b;
+ var a = this.a;
+ out.r = r + (to.r - r) * ratio;
+ out.g = g + (to.g - g) * ratio;
+ out.b = b + (to.b - b) * ratio;
+ out.a = a + (to.a - a) * ratio;
+ return out;
+ };
+
+ /**
+ * !#en TODO
+ * !#zh 转换为方便阅读的字符串。
+ * @method toString
+ * @return {String}
+ * @example
+ * var color = cc.Color.WHITE;
+ * color.toString(); // "rgba(255, 255, 255, 255)"
+ */
+ toString (): string {
+ return "rgba(" +
+ this.r.toFixed() + ", " +
+ this.g.toFixed() + ", " +
+ this.b.toFixed() + ", " +
+ this.a.toFixed() + ")";
+ };
+
+ /**
+ * !#en Get or set red channel value
+ * !#zh 获取或者设置红色通道
+ * @property {number} r
+ */
+ get r (): number {
+ return this.getR();
+ }
+ set r (v: number) {
+ this.setR(v);
+ }
+
+ /**
+ * !#en Get or set green channel value
+ * !#zh 获取或者设置绿色通道
+ * @property {number} g
+ */
+ get g (): number {
+ return this.getG();
+ }
+ set g (v: number) {
+ this.setG(v);
+ }
+
+ /**
+ * !#en Get or set blue channel value
+ * !#zh 获取或者设置蓝色通道
+ * @property {number} b
+ */
+ get b (): number {
+ return this.getB();
+ }
+ set b (v: number) {
+ this.setB(v);
+ }
+
+ /**
+ * !#en Get or set alpha channel value
+ * !#zh 获取或者设置透明通道
+ * @property {number} a
+ */
+ get a (): number {
+ return this.getA();
+ }
+ set a (v: number) {
+ this.setA(v);
+ }
+
+ /**
+ * !#en Gets red channel value
+ * !#zh 获取当前颜色的红色值。
+ * @method getR
+ * @return {Number} red value.
+ */
+ getR (): number {
+ return this._val & 0x000000ff;
+ }
+ /**
+ * !#en Sets red value and return the current color object
+ * !#zh 设置当前的红色值,并返回当前对象。
+ * @method setR
+ * @param {Number} red - the new Red component.
+ * @return {Color} this color.
+ * @example
+ * var color = new cc.Color();
+ * color.setR(255); // Color {r: 255, g: 0, b: 0, a: 255}
+ */
+ setR (red): this {
+ red = ~~misc.clampf(red, 0, 255);
+ this._val = ((this._val & 0xffffff00) | red) >>> 0;
+ return this;
+ }
+ /**
+ * !#en Gets green channel value
+ * !#zh 获取当前颜色的绿色值。
+ * @method getG
+ * @return {Number} green value.
+ */
+ getG (): number {
+ return (this._val & 0x0000ff00) >> 8;
+ }
+ /**
+ * !#en Sets green value and return the current color object
+ * !#zh 设置当前的绿色值,并返回当前对象。
+ * @method setG
+ * @param {Number} green - the new Green component.
+ * @return {Color} this color.
+ * @example
+ * var color = new cc.Color();
+ * color.setG(255); // Color {r: 0, g: 255, b: 0, a: 255}
+ */
+ setG (green): this {
+ green = ~~misc.clampf(green, 0, 255);
+ this._val = ((this._val & 0xffff00ff) | (green << 8)) >>> 0;
+ return this;
+ }
+ /**
+ * !#en Gets blue channel value
+ * !#zh 获取当前颜色的蓝色值。
+ * @method getB
+ * @return {Number} blue value.
+ */
+ getB (): number {
+ return (this._val & 0x00ff0000) >> 16;
+ }
+ /**
+ * !#en Sets blue value and return the current color object
+ * !#zh 设置当前的蓝色值,并返回当前对象。
+ * @method setB
+ * @param {Number} blue - the new Blue component.
+ * @return {Color} this color.
+ * @example
+ * var color = new cc.Color();
+ * color.setB(255); // Color {r: 0, g: 0, b: 255, a: 255}
+ */
+ setB (blue): this {
+ blue = ~~misc.clampf(blue, 0, 255);
+ this._val = ((this._val & 0xff00ffff) | (blue << 16)) >>> 0;
+ return this;
+ }
+ /**
+ * !#en Gets alpha channel value
+ * !#zh 获取当前颜色的透明度值。
+ * @method getA
+ * @return {Number} alpha value.
+ */
+ getA (): number {
+ return (this._val & 0xff000000) >>> 24;
+ }
+ /**
+ * !#en Sets alpha value and return the current color object
+ * !#zh 设置当前的透明度,并返回当前对象。
+ * @method setA
+ * @param {Number} alpha - the new Alpha component.
+ * @return {Color} this color.
+ * @example
+ * var color = new cc.Color();
+ * color.setA(0); // Color {r: 0, g: 0, b: 0, a: 0}
+ */
+ setA (alpha): this {
+ alpha = ~~misc.clampf(alpha, 0, 255);
+ this._val = ((this._val & 0x00ffffff) | (alpha << 24)) >>> 0;
+ return this;
+ }
+
+ /**
+ * !#en Convert color to css format.
+ * !#zh 转换为 CSS 格式。
+ * @method toCSS
+ * @param {String} [opt="rgba"] - "rgba", "rgb", "#rgb" or "#rrggbb".
+ * @return {String}
+ * @example
+ * var color = cc.Color.BLACK;
+ * color.toCSS(); // "rgba(0,0,0,1.00)";
+ * color.toCSS("rgba"); // "rgba(0,0,0,1.00)";
+ * color.toCSS("rgb"); // "rgba(0,0,0)";
+ * color.toCSS("#rgb"); // "#000";
+ * color.toCSS("#rrggbb"); // "#000000";
+ */
+ toCSS (opt: string): string {
+ if (!opt || opt === 'rgba') {
+ return "rgba(" +
+ this.r + "," +
+ this.g + "," +
+ this.b + "," +
+ (this.a / 255).toFixed(2) + ")"
+ ;
+ }
+ else if (opt === 'rgb') {
+ return "rgb(" +
+ this.r + "," +
+ this.g + "," +
+ this.b + ")"
+ ;
+ }
+ else {
+ return '#' + this.toHEX(opt);
+ }
+ }
+
+ /**
+ * !#en Read hex string and store color data into the current color object, the hex string must be formated as rgba or rgb.
+ * !#zh 读取 16 进制颜色。
+ * @method fromHEX
+ * @param {String} hexString
+ * @return {Color}
+ * @chainable
+ * @example
+ * var color = cc.Color.BLACK;
+ * color.fromHEX("#FFFF33"); // Color {r: 255, g: 255, b: 51, a: 255};
+ */
+ fromHEX (hexString: string): this {
+ hexString = (hexString.indexOf('#') === 0) ? hexString.substring(1) : hexString;
+ let r = parseInt(hexString.substr(0, 2), 16) || 0;
+ let g = parseInt(hexString.substr(2, 2), 16) || 0;
+ let b = parseInt(hexString.substr(4, 2), 16) || 0;
+ let a = parseInt(hexString.substr(6, 2), 16) || 255;
+ this._val = ((a << 24) >>> 0) + (b << 16) + (g << 8) + r;
+ return this;
+ }
+
+ /**
+ * !#en convert Color to HEX color string.
+ * !#zh 转换为 16 进制。
+ * @method toHEX
+ * @param {String} [fmt="#rrggbb"] - "#rgb", "#rrggbb" or "#rrggbbaa".
+ * @return {String}
+ * @example
+ * var color = cc.Color.BLACK;
+ * color.toHEX("#rgb"); // "000";
+ * color.toHEX("#rrggbb"); // "000000";
+ */
+ toHEX (fmt): string {
+ const prefix = '0';
+ // #rrggbb
+ let hex = [
+ (this.r < 16 ? prefix : '') + (this.r).toString(16),
+ (this.g < 16 ? prefix : '') + (this.g).toString(16),
+ (this.b < 16 ? prefix : '') + (this.b).toString(16),
+ ];
+ if (fmt === '#rgb') {
+ hex[0] = hex[0][0];
+ hex[1] = hex[1][0];
+ hex[2] = hex[2][0];
+ }
+ else if (fmt === '#rrggbbaa') {
+ hex.push((this.a < 16 ? prefix : '') + (this.a).toString(16));
+ }
+ return hex.join('');
+ };
+
+ /**
+ * !#en Convert to 24bit rgb value.
+ * !#zh 转换为 24bit 的 RGB 值。
+ * @method toRGBValue
+ * @return {Number}
+ * @example
+ * var color = cc.Color.YELLOW;
+ * color.toRGBValue(); // 16771844;
+ */
+ toRGBValue (): number {
+ return this._val & 0x00ffffff;
+ }
+
+ /**
+ * !#en Read HSV model color and convert to RGB color
+ * !#zh 读取 HSV(色彩模型)格式。
+ * @method fromHSV
+ * @param {Number} h
+ * @param {Number} s
+ * @param {Number} v
+ * @return {Color}
+ * @chainable
+ * @example
+ * var color = cc.Color.YELLOW;
+ * color.fromHSV(0, 0, 1); // Color {r: 255, g: 255, b: 255, a: 255};
+ */
+ fromHSV (h, s, v): this {
+ var r, g, b;
+ if (s === 0) {
+ r = g = b = v;
+ }
+ else {
+ if (v === 0) {
+ r = g = b = 0;
+ }
+ else {
+ if (h === 1) h = 0;
+ h *= 6;
+ var i = Math.floor(h);
+ var f = h - i;
+ var p = v * (1 - s);
+ var q = v * (1 - (s * f));
+ var t = v * (1 - (s * (1 - f)));
+ switch (i) {
+ case 0:
+ r = v;
+ g = t;
+ b = p;
+ break;
+
+ case 1:
+ r = q;
+ g = v;
+ b = p;
+ break;
+
+ case 2:
+ r = p;
+ g = v;
+ b = t;
+ break;
+
+ case 3:
+ r = p;
+ g = q;
+ b = v;
+ break;
+
+ case 4:
+ r = t;
+ g = p;
+ b = v;
+ break;
+
+ case 5:
+ r = v;
+ g = p;
+ b = q;
+ break;
+ }
+ }
+ }
+ r *= 255;
+ g *= 255;
+ b *= 255;
+ this._val = ((this.a << 24) >>> 0) + (b << 16) + (g << 8) + (r|0);
+ return this;
+ }
+
+ /**
+ * !#en Transform to HSV model color
+ * !#zh 转换为 HSV(色彩模型)格式。
+ * @method toHSV
+ * @return {Object} - {h: number, s: number, v: number}.
+ * @example
+ * var color = cc.Color.YELLOW;
+ * color.toHSV(); // Object {h: 0.1533864541832669, s: 0.9843137254901961, v: 1};
+ */
+ toHSV () {
+ var r = this.r / 255;
+ var g = this.g / 255;
+ var b = this.b / 255;
+ var hsv = { h: 0, s: 0, v: 0 };
+ var max = Math.max(r, g, b);
+ var min = Math.min(r, g, b);
+ var delta = 0;
+ hsv.v = max;
+ hsv.s = max ? (max - min) / max : 0;
+ if (!hsv.s) hsv.h = 0;
+ else {
+ delta = max - min;
+ if (r === max) hsv.h = (g - b) / delta;
+ else if (g === max) hsv.h = 2 + (b - r) / delta;
+ else hsv.h = 4 + (r - g) / delta;
+ hsv.h /= 6;
+ if (hsv.h < 0) hsv.h += 1.0;
+ }
+ return hsv;
+ }
+
+ /**
+ * !#en Set the color
+ * !#zh 设置颜色
+ * @method set
+ * @typescript
+ * set (color: Color): Color
+ * @param {Color} color
+ */
+ set (color: Color): this {
+ if (color._val) {
+ this._val = color._val;
+ }
+ else {
+ this.r = color.r;
+ this.g = color.g;
+ this.b = color.b;
+ this.a = color.a;
+ }
+ return this;
+ }
+
+ _fastSetA (alpha) {
+ this._val = ((this._val & 0x00ffffff) | (alpha << 24)) >>> 0;
+ }
+
+ /**
+ * !#en Multiplies the current color by the specified color
+ * !#zh 将当前颜色乘以与指定颜色
+ * @method multiply
+ * @return {Color}
+ * @param {Color} other
+ */
+ multiply (other: Color) {
+ let r = ((this._val & 0x000000ff) * other.r) >> 8;
+ let g = ((this._val & 0x0000ff00) * other.g) >> 8;
+ let b = ((this._val & 0x00ff0000) * other.b) >> 8;
+ let a = ((this._val & 0xff000000) >>> 8) * other.a;
+ this._val = (a & 0xff000000) | (b & 0x00ff0000) | (g & 0x0000ff00) | (r & 0x000000ff);
+ return this;
+ }
+}
+
+CCClass.fastDefine('cc.Color', Color, { r: 0, g: 0, b: 0, a: 255 });
+
+
+cc.Color = Color;
+
+/**
+ * @module cc
+ */
+
+/**
+ * !#en
+ * The convenience method to create a new {{#crossLink "Color/Color:method"}}cc.Color{{/crossLink}}
+ * Alpha channel is optional. Default value is 255.
+ *
+ * !#zh
+ * 通过该方法来创建一个新的 {{#crossLink "Color/Color:method"}}cc.Color{{/crossLink}} 对象。
+ * Alpha 通道是可选的。默认值是 255。
+ *
+ * @method color
+ * @param {Number} [r=0]
+ * @param {Number} [g=0]
+ * @param {Number} [b=0]
+ * @param {Number} [a=255]
+ * @return {Color}
+ * @example {@link cocos2d/core/value-types/CCColor/color.js}
+ */
+cc.color = function color (r, g, b, a) {
+ if (typeof r === 'string') {
+ var result = new Color();
+ return result.fromHEX(r);
+ }
+ if (typeof r === 'object') {
+ return new Color(r.r, r.g, r.b, r.a);
+ }
+ return new Color(r, g, b, a);
+};
diff --git a/cocos2d/core/value-types/index.ts b/cocos2d/core/value-types/index.ts
new file mode 100644
index 00000000000..560e52f2a9d
--- /dev/null
+++ b/cocos2d/core/value-types/index.ts
@@ -0,0 +1,39 @@
+/****************************************************************************
+ Copyright (c) 2013-2016 Chukong Technologies Inc.
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ https://www.cocos.com/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You shall
+ not use Cocos Creator software for developing other software or tools that's
+ used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+
+export { default as Vec2 } from './vec2';
+export { default as Vec3} from './vec3';
+export { default as Vec4} from './vec4';
+export { default as Mat4} from './mat4';
+export { default as Mat3} from './mat3';
+export { default as Rect} from './rect';
+export { default as Size} from './size';
+export { default as Color} from './color';
+export { default as Quat} from './quat';
+export { default as Trs} from './trs';
+export * from './utils';
+
+cc.math = module.exports;
diff --git a/cocos2d/core/value-types/mat3.ts b/cocos2d/core/value-types/mat3.ts
new file mode 100644
index 00000000000..4ad03c283dc
--- /dev/null
+++ b/cocos2d/core/value-types/mat3.ts
@@ -0,0 +1,925 @@
+import { EPSILON, FLOAT_ARRAY_TYPE } from '../value-types/utils';
+import Vec3 from './vec3';
+import Vec2 from './vec2';
+import Mat4 from './mat4';
+import Quat from './quat';
+
+/**
+ * Mathematical 3x3 matrix.
+ *
+ * NOTE: we use column-major matrix for all matrix calculation.
+ *
+ * This may lead to some confusion when referencing OpenGL documentation,
+ * however, which represents out all matricies in column-major format.
+ * This means that while in code a matrix may be typed out as:
+ *
+ * [1, 0, 0, 0,
+ * 0, 1, 0, 0,
+ * 0, 0, 1, 0,
+ * x, y, z, 0]
+ *
+ * The same matrix in the [OpenGL documentation](https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTranslate.xml)
+ * is written as:
+ *
+ * 1 0 0 x
+ * 0 1 0 y
+ * 0 0 1 z
+ * 0 0 0 0
+ *
+ * Please rest assured, however, that they are the same thing!
+ * This is not unique to glMatrix, either, as OpenGL developers have long been confused by the
+ * apparent lack of consistency between the memory layout and the documentation.
+ *
+ * @class Mat3
+ * @extends ValueType
+ */
+export default class Mat3 {
+ static sub = Mat3.subtract;
+ static mul = Mat3.multiply;
+
+ /**
+ * Identity of Mat3
+ * @property {Mat3} IDENTITY
+ * @static
+ */
+ static IDENTITY = Object.freeze(new Mat3());
+
+ /**
+ * Creates a matrix, with elements specified separately.
+ *
+ * @param {Number} m00 - Value assigned to element at column 0 row 0.
+ * @param {Number} m01 - Value assigned to element at column 0 row 1.
+ * @param {Number} m02 - Value assigned to element at column 0 row 2.
+ * @param {Number} m03 - Value assigned to element at column 1 row 0.
+ * @param {Number} m04 - Value assigned to element at column 1 row 1.
+ * @param {Number} m05 - Value assigned to element at column 1 row 2.
+ * @param {Number} m06 - Value assigned to element at column 2 row 0.
+ * @param {Number} m07 - Value assigned to element at column 2 row 1.
+ * @param {Number} m08 - Value assigned to element at column 2 row 2.
+ * @returns {Mat3} The newly created matrix.
+ * @static
+ */
+ static create (m00: number = 1, m01: number = 0, m02: number = 0, m03: number = 0, m04: number = 1, m05: number = 0, m06: number = 0, m07: number = 0, m08: number = 1): Mat3 {
+ return new Mat3(m00, m01, m02, m03, m04, m05, m06, m07, m08);
+ }
+
+ /**
+ * Clone a matrix.
+ *
+ * @param {Mat3} a - Matrix to clone.
+ * @returns {Mat3} The newly created matrix.
+ * @static
+ */
+ static clone (a: Mat3): Mat3 {
+ let am = a.m;
+ return new Mat3(
+ am[0], am[1], am[2],
+ am[3], am[4], am[5],
+ am[6], am[7], am[8]
+ );
+ }
+
+ /**
+ * Copy content of a matrix into another.
+ *
+ * @param {Mat3} out - Matrix to modified.
+ * @param {Mat3} a - The specified matrix.
+ * @returns {Mat3} out.
+ * @static
+ */
+ static copy (out: Mat3, a: Mat3): Mat3 {
+ out.m.set(a.m);
+ return out;
+ }
+
+ /**
+ * Sets the elements of a matrix to the given values.
+ *
+ * @param {Mat3} out - The matrix to modified.
+ * @param {Number} m00 - Value assigned to element at column 0 row 0.
+ * @param {Number} m01 - Value assigned to element at column 0 row 1.
+ * @param {Number} m02 - Value assigned to element at column 0 row 2.
+ * @param {Number} m10 - Value assigned to element at column 1 row 0.
+ * @param {Number} m11 - Value assigned to element at column 1 row 1.
+ * @param {Number} m12 - Value assigned to element at column 1 row 2.
+ * @param {Number} m20 - Value assigned to element at column 2 row 0.
+ * @param {Number} m21 - Value assigned to element at column 2 row 1.
+ * @param {Number} m22 - Value assigned to element at column 2 row 2.
+ * @returns {Mat3} out.
+ * @static
+ */
+ static set (out: Mat3, m00: number, m01: number, m02: number, m10: number, m11: number, m12: number, m20: number, m21: number, m22: number): Mat3 {
+ let outm = out.m;
+ outm[0] = m00;
+ outm[1] = m01;
+ outm[2] = m02;
+ outm[3] = m10;
+ outm[4] = m11;
+ outm[5] = m12;
+ outm[6] = m20;
+ outm[7] = m21;
+ outm[8] = m22;
+ return out;
+ }
+
+ /**
+ * return an identity matrix.
+ *
+ * @returns {Mat3} out.
+ * @static
+ */
+ static identity (out: Mat3): Mat3 {
+ let outm = out.m;
+ outm[0] = 1;
+ outm[1] = 0;
+ outm[2] = 0;
+ outm[3] = 0;
+ outm[4] = 1;
+ outm[5] = 0;
+ outm[6] = 0;
+ outm[7] = 0;
+ outm[8] = 1;
+ return out;
+ }
+
+ /**
+ * Transposes a matrix.
+ *
+ * @param {Mat3} out - Matrix to store result.
+ * @param {Mat3} a - Matrix to transpose.
+ * @returns {Mat3} out.
+ * @static
+ */
+ static transpose (out: Mat3, a: Mat3): Mat3 {
+ let am = a.m, outm = out.m;
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ let a01 = am[1], a02 = am[2], a12 = am[5];
+ outm[1] = am[3];
+ outm[2] = am[6];
+ outm[3] = a01;
+ outm[5] = am[7];
+ outm[6] = a02;
+ outm[7] = a12;
+ } else {
+ outm[0] = am[0];
+ outm[1] = am[3];
+ outm[2] = am[6];
+ outm[3] = am[1];
+ outm[4] = am[4];
+ outm[5] = am[7];
+ outm[6] = am[2];
+ outm[7] = am[5];
+ outm[8] = am[8];
+ }
+
+ return out;
+ }
+
+ /**
+ * Inverts a matrix.
+ *
+ * @param {Mat3} out - Matrix to store result.
+ * @param {Mat3} a - Matrix to invert.
+ * @returns {Mat3} out.
+ * @static
+ */
+ static invert (out: Mat3, a: Mat3): Mat3 {
+ let am = a.m, outm = out.m;
+ let a00 = am[0], a01 = am[1], a02 = am[2],
+ a10 = am[3], a11 = am[4], a12 = am[5],
+ a20 = am[6], a21 = am[7], a22 = am[8];
+
+ let b01 = a22 * a11 - a12 * a21;
+ let b11 = -a22 * a10 + a12 * a20;
+ let b21 = a21 * a10 - a11 * a20;
+
+ // Calculate the determinant
+ let det = a00 * b01 + a01 * b11 + a02 * b21;
+
+ if (!det) {
+ return out;
+ }
+ det = 1.0 / det;
+
+ outm[0] = b01 * det;
+ outm[1] = (-a22 * a01 + a02 * a21) * det;
+ outm[2] = (a12 * a01 - a02 * a11) * det;
+ outm[3] = b11 * det;
+ outm[4] = (a22 * a00 - a02 * a20) * det;
+ outm[5] = (-a12 * a00 + a02 * a10) * det;
+ outm[6] = b21 * det;
+ outm[7] = (-a21 * a00 + a01 * a20) * det;
+ outm[8] = (a11 * a00 - a01 * a10) * det;
+ return out;
+ }
+
+ /**
+ * Calculates the adjugate of a matrix.
+ *
+ * @param {Mat3} out - Matrix to store result.
+ * @param {Mat3} a - Matrix to calculate.
+ * @returns {Mat3} out.
+ * @static
+ */
+ static adjoint (out: Mat3, a: Mat3): Mat3 {
+ let am = a.m, outm = out.m;
+ let a00 = am[0], a01 = am[1], a02 = am[2],
+ a10 = am[3], a11 = am[4], a12 = am[5],
+ a20 = am[6], a21 = am[7], a22 = am[8];
+
+ outm[0] = (a11 * a22 - a12 * a21);
+ outm[1] = (a02 * a21 - a01 * a22);
+ outm[2] = (a01 * a12 - a02 * a11);
+ outm[3] = (a12 * a20 - a10 * a22);
+ outm[4] = (a00 * a22 - a02 * a20);
+ outm[5] = (a02 * a10 - a00 * a12);
+ outm[6] = (a10 * a21 - a11 * a20);
+ outm[7] = (a01 * a20 - a00 * a21);
+ outm[8] = (a00 * a11 - a01 * a10);
+ return out;
+ }
+
+ /**
+ * Calculates the determinant of a matrix.
+ *
+ * @param {Mat3} a - Matrix to calculate.
+ * @returns {Number} Determinant of a.
+ * @static
+ */
+ static determinant (a: Mat3): number {
+ let am = a.m;
+ let a00 = am[0], a01 = am[1], a02 = am[2],
+ a10 = am[3], a11 = am[4], a12 = am[5],
+ a20 = am[6], a21 = am[7], a22 = am[8];
+
+ return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+ }
+
+ /**
+ * Multiply two matrices explicitly.
+ *
+ * @param {Mat3} out - Matrix to store result.
+ * @param {Mat3} a - The first operand.
+ * @param {Mat3} b - The second operand.
+ * @returns {Mat3} out.
+ * @static
+ */
+ static multiply (out: Mat3, a: Mat3, b: Mat3): Mat3 {
+ let am = a.m, bm = b.m, outm = out.m;
+ let a00 = am[0], a01 = am[1], a02 = am[2],
+ a10 = am[3], a11 = am[4], a12 = am[5],
+ a20 = am[6], a21 = am[7], a22 = am[8];
+
+ let b00 = bm[0], b01 = bm[1], b02 = bm[2];
+ let b10 = bm[3], b11 = bm[4], b12 = bm[5];
+ let b20 = bm[6], b21 = bm[7], b22 = bm[8];
+
+ outm[0] = b00 * a00 + b01 * a10 + b02 * a20;
+ outm[1] = b00 * a01 + b01 * a11 + b02 * a21;
+ outm[2] = b00 * a02 + b01 * a12 + b02 * a22;
+
+ outm[3] = b10 * a00 + b11 * a10 + b12 * a20;
+ outm[4] = b10 * a01 + b11 * a11 + b12 * a21;
+ outm[5] = b10 * a02 + b11 * a12 + b12 * a22;
+
+ outm[6] = b20 * a00 + b21 * a10 + b22 * a20;
+ outm[7] = b20 * a01 + b21 * a11 + b22 * a21;
+ outm[8] = b20 * a02 + b21 * a12 + b22 * a22;
+ return out;
+ }
+
+ /**
+ * !#en Take the first third order of the fourth order matrix and multiply by the third order matrix
+ * !#zh 取四阶矩阵的前三阶,与三阶矩阵相乘
+ * @param {Mat3} out - Matrix to store result.
+ * @param {Mat3} a - The first operand.
+ * @param {Mat3} b - The second operand.
+ * @returns {Mat3} out.
+ * @static
+ */
+ static multiplyMat4 (out: Out, a: Out, b: IMat4Like) {
+ let am = a.m, bm = b.m, outm = out.m;
+ let a00 = am[0], a01 = am[1], a02 = am[2],
+ a10 = am[3], a11 = am[4], a12 = am[5],
+ a20 = am[6], a21 = am[7], a22 = am[8];
+
+ const b00 = bm[0], b01 = bm[1], b02 = bm[2];
+ const b10 = bm[4], b11 = bm[5], b12 = bm[6];
+ const b20 = bm[8], b21 = bm[9], b22 = bm[10];
+
+ outm[0] = b00 * a00 + b01 * a10 + b02 * a20;
+ outm[1] = b00 * a01 + b01 * a11 + b02 * a21;
+ outm[2] = b00 * a02 + b01 * a12 + b02 * a22;
+ outm[3] = b10 * a00 + b11 * a10 + b12 * a20;
+ outm[4] = b10 * a01 + b11 * a11 + b12 * a21;
+ outm[5] = b10 * a02 + b11 * a12 + b12 * a22;
+ outm[6] = b20 * a00 + b21 * a10 + b22 * a20;
+ outm[7] = b20 * a01 + b21 * a11 + b22 * a21;
+ outm[8] = b20 * a02 + b21 * a12 + b22 * a22;
+ return out;
+ }
+
+ /**
+ * Multiply a matrix with a translation matrix given by a translation offset.
+ *
+ * @param {Mat3} out - Matrix to store result.
+ * @param {Mat3} a - Matrix to multiply.
+ * @param {vec2} v - The translation offset.
+ * @returns {Mat3} out.
+ * @static
+ */
+ static translate (out: Mat3, a: Mat3, v: Vec2): Mat3 {
+ let am = a.m, outm = out.m;
+ let a00 = am[0], a01 = am[1], a02 = am[2],
+ a10 = am[3], a11 = am[4], a12 = am[5],
+ a20 = am[6], a21 = am[7], a22 = am[8];
+ let x = v.x, y = v.y;
+
+ outm[0] = a00;
+ outm[1] = a01;
+ outm[2] = a02;
+
+ outm[3] = a10;
+ outm[4] = a11;
+ outm[5] = a12;
+
+ outm[6] = x * a00 + y * a10 + a20;
+ outm[7] = x * a01 + y * a11 + a21;
+ outm[8] = x * a02 + y * a12 + a22;
+ return out;
+ }
+
+ /**
+ * Rotates a matrix by the given angle.
+ *
+ * @param {Mat3} out - Matrix to store result.
+ * @param {Mat3} a - Matrix to rotate.
+ * @param {Number} rad - The rotation angle.
+ * @returns {Mat3} out
+ * @static
+ */
+ static rotate (out: Mat3, a: Mat3, rad: number): Mat3 {
+ let am = a.m, outm = out.m;
+ let a00 = am[0], a01 = am[1], a02 = am[2],
+ a10 = am[3], a11 = am[4], a12 = am[5],
+ a20 = am[6], a21 = am[7], a22 = am[8];
+
+ let s = Math.sin(rad);
+ let c = Math.cos(rad);
+
+ outm[0] = c * a00 + s * a10;
+ outm[1] = c * a01 + s * a11;
+ outm[2] = c * a02 + s * a12;
+
+ outm[3] = c * a10 - s * a00;
+ outm[4] = c * a11 - s * a01;
+ outm[5] = c * a12 - s * a02;
+
+ outm[6] = a20;
+ outm[7] = a21;
+ outm[8] = a22;
+ return out;
+ }
+
+ /**
+ * Multiply a matrix with a scale matrix given by a scale vector.
+ *
+ * @param {Mat3} out - Matrix to store result.
+ * @param {Mat3} a - Matrix to multiply.
+ * @param {vec2} v - The scale vector.
+ * @returns {Mat3} out
+ **/
+ static scale (out: Mat3, a: Mat3, v: Vec2): Mat3 {
+ let x = v.x, y = v.y;
+ let am = a.m, outm = out.m;
+
+ outm[0] = x * am[0];
+ outm[1] = x * am[1];
+ outm[2] = x * am[2];
+
+ outm[3] = y * am[3];
+ outm[4] = y * am[4];
+ outm[5] = y * am[5];
+
+ outm[6] = am[6];
+ outm[7] = am[7];
+ outm[8] = am[8];
+ return out;
+ }
+
+ /**
+ * Copies the upper-left 3x3 values of a 4x4 matrix into a 3x3 matrix.
+ *
+ * @param {Mat3} out - Matrix to store result.
+ * @param {mat4} a - The 4x4 matrix.
+ * @returns {Mat3} out.
+ * @static
+ */
+ static fromMat4 (out: Mat3, a: Mat4): Mat3 {
+ let am = a.m, outm = out.m;
+ outm[0] = am[0];
+ outm[1] = am[1];
+ outm[2] = am[2];
+ outm[3] = am[4];
+ outm[4] = am[5];
+ outm[5] = am[6];
+ outm[6] = am[8];
+ outm[7] = am[9];
+ outm[8] = am[10];
+ return out;
+ }
+
+ /**
+ * Creates a matrix from a translation offset.
+ * This is equivalent to (but much faster than):
+ *
+ * mat3.identity(dest);
+ * mat3.translate(dest, dest, vec);
+ *
+ * @param {Mat3} out - Matrix to store result.
+ * @param {vec2} v - The translation offset.
+ * @returns {Mat3} out.
+ * @static
+ */
+ static fromTranslation (out: Mat3, v: Vec2): Mat3 {
+ let outm = out.m;
+ outm[0] = 1;
+ outm[1] = 0;
+ outm[2] = 0;
+ outm[3] = 0;
+ outm[4] = 1;
+ outm[5] = 0;
+ outm[6] = v.x;
+ outm[7] = v.y;
+ outm[8] = 1;
+ return out;
+ }
+
+ /**
+ * Creates a matrix from a given angle.
+ * This is equivalent to (but much faster than):
+ *
+ * mat3.identity(dest);
+ * mat3.rotate(dest, dest, rad);
+ *
+ * @param {Mat3} out - Matrix to store result.
+ * @param {Number} rad - The rotation angle.
+ * @returns {Mat3} out.
+ * @static
+ */
+ static fromRotation (out: Mat3, rad: number): Mat3 {
+ let s = Math.sin(rad), c = Math.cos(rad);
+ let outm = out.m;
+
+ outm[0] = c;
+ outm[1] = s;
+ outm[2] = 0;
+
+ outm[3] = -s;
+ outm[4] = c;
+ outm[5] = 0;
+
+ outm[6] = 0;
+ outm[7] = 0;
+ outm[8] = 1;
+ return out;
+ }
+
+ /**
+ * Creates a matrix from a scale vector.
+ * This is equivalent to (but much faster than):
+ *
+ * mat3.identity(dest);
+ * mat3.scale(dest, dest, vec);
+ *
+ * @param {Mat3} out - Matrix to store result.
+ * @param {vec2} v - Scale vector.
+ * @returns {Mat3} out.
+ * @static
+ */
+ static fromScaling (out: Mat3, v: Vec2): Mat3 {
+ let outm = out.m;
+ outm[0] = v.x;
+ outm[1] = 0;
+ outm[2] = 0;
+
+ outm[3] = 0;
+ outm[4] = v.y;
+ outm[5] = 0;
+
+ outm[6] = 0;
+ outm[7] = 0;
+ outm[8] = 1;
+ return out;
+ }
+
+ /**
+ * Calculates a 3x3 matrix from the given quaternion.
+ *
+ * @param {Mat3} out - Matrix to store result.
+ * @param {quat} q - The quaternion.
+ *
+ * @returns {Mat3} out.
+ * @static
+ */
+ static fromQuat (out: Mat3, q: Quat): Mat3 {
+ let outm = out.m;
+ let x = q.x, y = q.y, z = q.z, w = q.w;
+ let x2 = x + x;
+ let y2 = y + y;
+ let z2 = z + z;
+
+ let xx = x * x2;
+ let yx = y * x2;
+ let yy = y * y2;
+ let zx = z * x2;
+ let zy = z * y2;
+ let zz = z * z2;
+ let wx = w * x2;
+ let wy = w * y2;
+ let wz = w * z2;
+
+ outm[0] = 1 - yy - zz;
+ outm[3] = yx - wz;
+ outm[6] = zx + wy;
+
+ outm[1] = yx + wz;
+ outm[4] = 1 - xx - zz;
+ outm[7] = zy - wx;
+
+ outm[2] = zx - wy;
+ outm[5] = zy + wx;
+ outm[8] = 1 - xx - yy;
+
+ return out;
+ }
+
+ /**
+ * Calculates a 3x3 matrix from view direction and up direction.
+ *
+ * @param {Mat3} out - Matrix to store result.
+ * @param {vec3} view - View direction (must be normalized).
+ * @param {vec3} [up] - Up direction, default is (0,1,0) (must be normalized).
+ *
+ * @returns {Mat3} out
+ * @static
+ */
+ static fromViewUp (out: Mat3, view: Vec3, up?: Vec3): Mat3 {
+ let _fromViewUpIIFE = (function () {
+ let default_up = new Vec3(0, 1, 0);
+ let x = new Vec3();
+ let y = new Vec3();
+
+ return function (out, view, up) {
+ if (Vec3.lengthSqr(view) < EPSILON * EPSILON) {
+ Mat3.identity(out);
+ return out;
+ }
+
+ up = up || default_up;
+ Vec3.normalize(x, Vec3.cross(x, up, view));
+
+ if (Vec3.lengthSqr(x) < EPSILON * EPSILON) {
+ Mat3.identity(out);
+ return out;
+ }
+
+ Vec3.cross(y, view, x);
+ Mat3.set(
+ out,
+ x.x, x.y, x.z,
+ y.x, y.y, y.z,
+ view.x, view.y, view.z
+ );
+
+ return out;
+ };
+ })();
+ return _fromViewUpIIFE(out, view, up);
+ }
+
+ /**
+ * Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix.
+ *
+ * @param {Mat3} out - Matrix to store result.
+ * @param {mat4} a - A 4x4 matrix to derive the normal matrix from.
+ *
+ * @returns {Mat3} out.
+ * @static
+ */
+ static normalFromMat4 (out: Mat3, a: Mat4): Mat3 {
+ let am = a.m, outm = out.m;
+ let a00 = am[0], a01 = am[1], a02 = am[2], a03 = am[3],
+ a10 = am[4], a11 = am[5], a12 = am[6], a13 = am[7],
+ a20 = am[8], a21 = am[9], a22 = am[10], a23 = am[11],
+ a30 = am[12], a31 = am[13], a32 = am[14], a33 = am[15];
+
+ let b00 = a00 * a11 - a01 * a10;
+ let b01 = a00 * a12 - a02 * a10;
+ let b02 = a00 * a13 - a03 * a10;
+ let b03 = a01 * a12 - a02 * a11;
+ let b04 = a01 * a13 - a03 * a11;
+ let b05 = a02 * a13 - a03 * a12;
+ let b06 = a20 * a31 - a21 * a30;
+ let b07 = a20 * a32 - a22 * a30;
+ let b08 = a20 * a33 - a23 * a30;
+ let b09 = a21 * a32 - a22 * a31;
+ let b10 = a21 * a33 - a23 * a31;
+ let b11 = a22 * a33 - a23 * a32;
+
+ // Calculate the determinant
+ let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+ if (!det) {
+ return out;
+ }
+ det = 1.0 / det;
+
+ outm[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+ outm[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+ outm[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+
+ outm[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+ outm[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+ outm[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+
+ outm[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+ outm[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+ outm[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+
+ return out;
+ }
+
+ /**
+ * Returns Frobenius norm of a matrix.
+ *
+ * @param {Mat3} a - Matrix to calculate Frobenius norm of.
+ * @returns {Number} - The frobenius norm.
+ * @static
+ */
+ static frob (a: Mat3): number {
+ let am = a.m;
+ return (Math.sqrt(Math.pow(am[0], 2) + Math.pow(am[1], 2) + Math.pow(am[2], 2) + Math.pow(am[3], 2) + Math.pow(am[4], 2) + Math.pow(am[5], 2) + Math.pow(am[6], 2) + Math.pow(am[7], 2) + Math.pow(am[8], 2)));
+ }
+
+ /**
+ * Adds two matrices.
+ *
+ * @param {Mat3} out - Matrix to store result.
+ * @param {Mat3} a - The first operand.
+ * @param {Mat3} b - The second operand.
+ * @returns {Mat3} out.
+ * @static
+ */
+ static add (out: Mat3, a: Mat3, b: Mat3): Mat3 {
+ let am = a.m, bm = b.m, outm = out.m;
+ outm[0] = am[0] + bm[0];
+ outm[1] = am[1] + bm[1];
+ outm[2] = am[2] + bm[2];
+ outm[3] = am[3] + bm[3];
+ outm[4] = am[4] + bm[4];
+ outm[5] = am[5] + bm[5];
+ outm[6] = am[6] + bm[6];
+ outm[7] = am[7] + bm[7];
+ outm[8] = am[8] + bm[8];
+ return out;
+ }
+
+ /**
+ * Subtracts matrix b from matrix a.
+ *
+ * @param {Mat3} out - Matrix to store result.
+ * @param {Mat3} a - The first operand.
+ * @param {Mat3} b - The second operand.
+ * @returns {Mat3} out.
+ * @static
+ */
+ static subtract (out: Mat3, a: Mat3, b: Mat3): Mat3 {
+ let am = a.m, bm = b.m, outm = out.m;
+ outm[0] = am[0] - bm[0];
+ outm[1] = am[1] - bm[1];
+ outm[2] = am[2] - bm[2];
+ outm[3] = am[3] - bm[3];
+ outm[4] = am[4] - bm[4];
+ outm[5] = am[5] - bm[5];
+ outm[6] = am[6] - bm[6];
+ outm[7] = am[7] - bm[7];
+ outm[8] = am[8] - bm[8];
+ return out;
+ }
+
+ /**
+ * Multiply each element of a matrix by a scalar number.
+ *
+ * @param {Mat3} out - Matrix to store result.
+ * @param {Mat3} a - Matrix to scale
+ * @param {Number} b - The scale number.
+ * @returns {Mat3} out.
+ * @static
+ */
+ static multiplyScalar (out: Mat3, a: Mat3, b: number): Mat3 {
+ let am = a.m, outm = out.m;
+ outm[0] = am[0] * b;
+ outm[1] = am[1] * b;
+ outm[2] = am[2] * b;
+ outm[3] = am[3] * b;
+ outm[4] = am[4] * b;
+ outm[5] = am[5] * b;
+ outm[6] = am[6] * b;
+ outm[7] = am[7] * b;
+ outm[8] = am[8] * b;
+ return out;
+ }
+
+ /**
+ * Adds two matrices after multiplying each element of the second operand by a scalar number.
+ *
+ * @param {Mat3} out - Matrix to store result.
+ * @param {Mat3} a - The first operand.
+ * @param {Mat3} b - The second operand.
+ * @param {Number} scale - The scale number.
+ * @returns {Mat3} out.
+ * @static
+ */
+ static multiplyScalarAndAdd (out: Mat3, a: Mat3, b: Mat3, scale: number): Mat3 {
+ let am = a.m, bm = b.m, outm = out.m;
+ outm[0] = am[0] + (bm[0] * scale);
+ outm[1] = am[1] + (bm[1] * scale);
+ outm[2] = am[2] + (bm[2] * scale);
+ outm[3] = am[3] + (bm[3] * scale);
+ outm[4] = am[4] + (bm[4] * scale);
+ outm[5] = am[5] + (bm[5] * scale);
+ outm[6] = am[6] + (bm[6] * scale);
+ outm[7] = am[7] + (bm[7] * scale);
+ outm[8] = am[8] + (bm[8] * scale);
+ return out;
+ }
+
+ /**
+ * Returns whether the specified matrices are equal. (Compared using ===)
+ *
+ * @param {Mat3} a - The first matrix.
+ * @param {Mat3} b - The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ * @static
+ */
+ static exactEquals (a: Mat3, b: Mat3): boolean {
+ let am = a.m, bm = b.m;
+ return am[0] === bm[0] && am[1] === bm[1] && am[2] === bm[2] &&
+ am[3] === bm[3] && am[4] === bm[4] && am[5] === bm[5] &&
+ am[6] === bm[6] && am[7] === bm[7] && am[8] === bm[8];
+ }
+
+ /**
+ * Returns whether the specified matrices are approximately equal.
+ *
+ * @param {Mat3} a - The first matrix.
+ * @param {Mat3} b - The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ * @static
+ */
+ static equals (a: Mat3, b: Mat3): boolean {
+ let am = a.m, bm = b.m;
+ let a0 = am[0], a1 = am[1], a2 = am[2], a3 = am[3], a4 = am[4], a5 = am[5], a6 = am[6], a7 = am[7], a8 = am[8];
+ let b0 = bm[0], b1 = bm[1], b2 = bm[2], b3 = bm[3], b4 = bm[4], b5 = bm[5], b6 = bm[6], b7 = bm[7], b8 = bm[8];
+ return (
+ Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
+ Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
+ Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
+ Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&
+ Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&
+ Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&
+ Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&
+ Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) &&
+ Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8))
+ );
+ }
+
+ /**
+ * !#zh 矩阵转数组
+ * !#en Matrix transpose array
+ * @method toArray
+ * @typescript
+ * toArray > (out: Out, mat: IMat3Like, ofs?: number): Out
+ * @param ofs 数组内的起始偏移量
+ * @static
+ */
+ static toArray > (out: Out, mat: IMat3Like, ofs = 0) {
+ let m = mat.m;
+ for (let i = 0; i < 9; i++) {
+ out[ofs + i] = m[i];
+ }
+ return out;
+ }
+
+ /**
+ * !#zh 数组转矩阵
+ * !#en Transfer matrix array
+ * @method fromArray
+ * @typescript
+ * fromArray