初始化

This commit is contained in:
SmallMain
2022-06-25 00:23:03 +08:00
commit ef0589e8e5
2264 changed files with 617829 additions and 0 deletions

View File

@@ -0,0 +1,429 @@
/****************************************************************************
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 from '../../cocos2d/core/value-types/mat4';
const RenderFlow = require('../../cocos2d/core/renderer/render-flow');
const FLAG_TRANSFORM = RenderFlow.FLAG_TRANSFORM;
const EmptyHandle = function () {}
const ATTACHED_ROOT_NAME = 'ATTACHED_NODE_TREE';
const ATTACHED_PRE_NAME = 'ATTACHED_NODE:';
const limitNode = function (node) {
// attached node's world matrix update per frame
Object.defineProperty(node, '_worldMatDirty', {
get () { return true; },
set (value) {/* do nothing */}
});
// shield world matrix calculate interface
node._calculWorldMatrix = EmptyHandle;
node._mulMat = EmptyHandle;
};
let _tempMat4 = new Mat4();
/**
* @module sp
*/
/**
* !#en Attach node tool
* !#zh 挂点工具类
* @class sp.AttachUtil
*/
let AttachUtil = cc.Class({
name: 'sp.AttachUtil',
ctor () {
this._inited = false;
this._skeleton = null;
this._skeletonNode = null;
this._skeletonComp = null;
this._attachedRootNode = null;
this._attachedNodeArray = [];
this._boneIndexToNode = {};
},
init (skeletonComp) {
this._inited = true;
this._skeleton = skeletonComp._skeleton;
this._skeletonNode = skeletonComp.node;
this._skeletonComp = skeletonComp;
},
reset () {
this._inited = false;
this._skeleton = null;
this._skeletonNode = null;
this._skeletonComp = null;
},
_prepareAttachNode () {
let armature = this._skeleton;
if (!armature) {
return;
}
let rootNode = this._skeletonNode.getChildByName(ATTACHED_ROOT_NAME);
if (!rootNode || !rootNode.isValid) {
rootNode = new cc.Node(ATTACHED_ROOT_NAME);
limitNode(rootNode);
this._skeletonNode.addChild(rootNode);
}
let isCached = this._skeletonComp.isAnimationCached();
if (isCached && this._skeletonComp._frameCache) {
this._skeletonComp._frameCache.enableCacheAttachedInfo();
}
this._attachedRootNode = rootNode;
return rootNode;
},
_buildBoneAttachedNode (bone, boneIndex) {
let boneNodeName = ATTACHED_PRE_NAME + bone.data.name;
let boneNode = new cc.Node(boneNodeName);
this._buildBoneRelation(boneNode, bone, boneIndex);
return boneNode;
},
_buildBoneRelation (boneNode, bone, boneIndex) {
limitNode(boneNode);
boneNode._bone = bone;
boneNode._boneIndex = boneIndex;
this._attachedNodeArray.push(boneNode);
this._boneIndexToNode[boneIndex] = boneNode;
},
/**
* !#en Gets attached root node.
* !#zh 获取挂接节点树的根节点
* @method getAttachedRootNode
* @return {cc.Node}
*/
getAttachedRootNode () {
return this._attachedRootNode;
},
/**
* !#en Gets attached node which you want.
* !#zh 获得对应的挂点
* @method getAttachedNodes
* @param {String} boneName
* @return {Node[]}
*/
getAttachedNodes (boneName) {
let nodeArray = this._attachedNodeArray;
let res = [];
if (!this._inited) return res;
for (let i = 0, n = nodeArray.length; i < n; i++) {
let boneNode = nodeArray[i];
if (!boneNode || !boneNode.isValid) continue;
if (boneNode.name === ATTACHED_PRE_NAME + boneName) {
res.push(boneNode);
}
}
return res;
},
_rebuildNodeArray () {
let findMap = this._boneIndexToNode = {};
let oldNodeArray = this._attachedNodeArray;
let nodeArray = this._attachedNodeArray = [];
for (let i = 0, n = oldNodeArray.length; i < n; i++) {
let boneNode = oldNodeArray[i];
if (!boneNode || !boneNode.isValid || boneNode._toRemove) continue;
nodeArray.push(boneNode);
findMap[boneNode._boneIndex] = boneNode;
}
},
_sortNodeArray () {
let nodeArray = this._attachedNodeArray;
nodeArray.sort(function (a, b) {
return a._boneIndex < b._boneIndex? -1 : 1;
});
},
_getNodeByBoneIndex (boneIndex) {
let findMap = this._boneIndexToNode;
let boneNode = findMap[boneIndex];
if (!boneNode || !boneNode.isValid) return null;
return boneNode;
},
/**
* !#en Destroy attached node which you want.
* !#zh 销毁对应的挂点
* @method destroyAttachedNodes
* @param {String} boneName
*/
destroyAttachedNodes (boneName) {
if (!this._inited) return;
let nodeArray = this._attachedNodeArray;
let markTree = function (rootNode) {
let children = rootNode.children;
for (let i = 0, n = children.length; i < n; i++) {
let c = children[i];
if (c) markTree(c);
}
rootNode._toRemove = true;
}
for (let i = 0, n = nodeArray.length; i < n; i++) {
let boneNode = nodeArray[i];
if (!boneNode || !boneNode.isValid) continue;
let delName = boneNode.name.split(ATTACHED_PRE_NAME)[1];
if (delName === boneName) {
markTree(boneNode);
boneNode.removeFromParent(true);
boneNode.destroy();
nodeArray[i] = null;
}
}
this._rebuildNodeArray();
},
/**
* !#en Traverse all bones to generate the minimum node tree containing the given bone names, NOTE that make sure the skeleton has initialized before calling this interface.
* !#zh 遍历所有插槽,生成包含所有给定插槽名称的最小节点树,注意,调用该接口前请确保骨骼动画已经初始化好。
* @method generateAttachedNodes
* @param {String} boneName
* @return {Node[]} attached node array
*/
generateAttachedNodes (boneName) {
let targetNodes = [];
if (!this._inited) return targetNodes;
let rootNode = this._prepareAttachNode();
if (!rootNode) return targetNodes;
let res = [];
let bones = this._skeleton.bones;
for (let i = 0, n = bones.length; i < n; i++) {
let bone = bones[i];
let boneData = bone.data;
if (boneData.name == boneName) {
res.push(bone);
}
}
let buildBoneTree = function (bone) {
if (!bone) return;
let boneData = bone.data;
let boneNode = this._getNodeByBoneIndex(boneData.index);
if (boneNode) return boneNode;
boneNode = this._buildBoneAttachedNode(bone, boneData.index);
let parentBoneNode = buildBoneTree(bone.parent) || rootNode;
boneNode.parent = parentBoneNode;
return boneNode;
}.bind(this);
for (let i = 0, n = res.length; i < n; i++) {
let targetNode = buildBoneTree(res[i]);
targetNodes.push(targetNode);
}
this._sortNodeArray();
return targetNodes;
},
/**
* !#en Destroy all attached node.
* !#zh 销毁所有挂点
* @method destroyAllAttachedNodes
*/
destroyAllAttachedNodes () {
this._attachedRootNode = null;
this._attachedNodeArray.length = 0;
this._boneIndexToNode = {};
if (!this._inited) return;
let rootNode = this._skeletonNode.getChildByName(ATTACHED_ROOT_NAME);
if (rootNode) {
rootNode.removeFromParent(true);
rootNode.destroy();
rootNode = null;
}
},
/**
* !#en Traverse all bones to generate a tree containing all bones nodes, NOTE that make sure the skeleton has initialized before calling this interface.
* !#zh 遍历所有插槽,生成包含所有插槽的节点树,注意,调用该接口前请确保骨骼动画已经初始化好。
* @method generateAllAttachedNodes
* @return {cc.Node} root node
*/
generateAllAttachedNodes () {
if (!this._inited) return;
// clear all records
this._boneIndexToNode = {};
this._attachedNodeArray.length = 0;
let rootNode = this._prepareAttachNode();
if (!rootNode) return;
let bones = this._skeleton.bones;
for (let i = 0, n = bones.length; i < n; i++) {
let bone = bones[i];
let boneData = bone.data;
let parentNode = null;
if (bone.parent) {
let parentIndex = bone.parent.data.index;
parentNode = this._boneIndexToNode[parentIndex];
} else {
parentNode = rootNode;
}
if (parentNode) {
let boneNode = parentNode.getChildByName(ATTACHED_PRE_NAME + boneData.name);
if (!boneNode || !boneNode.isValid) {
boneNode = this._buildBoneAttachedNode(bone, boneData.index);
parentNode.addChild(boneNode);
} else {
this._buildBoneRelation(boneNode, bone, boneData.index);
}
}
}
return rootNode;
},
_hasAttachedNode () {
if (!this._inited) return false;
let attachedRootNode = this._skeletonNode.getChildByName(ATTACHED_ROOT_NAME);
return !!attachedRootNode;
},
_associateAttachedNode () {
if (!this._inited) return;
let rootNode = this._skeletonNode.getChildByName(ATTACHED_ROOT_NAME);
if (!rootNode || !rootNode.isValid) return;
this._attachedRootNode = rootNode;
// clear all records
this._boneIndexToNode = {};
let nodeArray = this._attachedNodeArray;
nodeArray.length = 0;
limitNode(rootNode);
if (!CC_NATIVERENDERER) {
let isCached = this._skeletonComp.isAnimationCached();
if (isCached && this._skeletonComp._frameCache) {
this._skeletonComp._frameCache.enableCacheAttachedInfo();
}
}
let bones = this._skeleton.bones;
for (let i = 0, n = bones.length; i < n; i++) {
let bone = bones[i];
let boneData = bone.data;
let parentNode = null;
if (bone.parent) {
let parentIndex = bone.parent.data.index;
parentNode = this._boneIndexToNode[parentIndex];
} else {
parentNode = rootNode;
}
if (parentNode) {
let boneNode = parentNode.getChildByName(ATTACHED_PRE_NAME + boneData.name);
if (boneNode && boneNode.isValid) {
this._buildBoneRelation(boneNode, bone, boneData.index);
}
}
}
},
_syncAttachedNode () {
if (!this._inited) return;
let rootNode = this._attachedRootNode;
let nodeArray = this._attachedNodeArray;
if (!rootNode || !rootNode.isValid) {
this._attachedRootNode = null;
nodeArray.length = 0;
return;
}
let rootMatrix = this._skeletonNode._worldMatrix;
Mat4.copy(rootNode._worldMatrix, rootMatrix);
rootNode._renderFlag &= ~FLAG_TRANSFORM;
let boneInfos = null;
let isCached = this._skeletonComp.isAnimationCached();
if (isCached) {
boneInfos = this._skeletonComp._curFrame && this._skeletonComp._curFrame.boneInfos;
} else {
boneInfos = this._skeleton.bones;
}
if (!boneInfos) return;
let mulMat = this._skeletonNode._mulMat;
let matrixHandle = function (nodeMat, parentMat, bone) {
let tm = _tempMat4.m;
tm[0] = bone.a;
tm[1] = bone.c;
tm[4] = bone.b;
tm[5] = bone.d;
tm[12] = bone.worldX;
tm[13] = bone.worldY;
mulMat(nodeMat, parentMat, _tempMat4);
};
let nodeArrayDirty = false;
for (let i = 0, n = nodeArray.length; i < n; i++) {
let boneNode = nodeArray[i];
// Node has been destroy
if (!boneNode || !boneNode.isValid) {
nodeArray[i] = null;
nodeArrayDirty = true;
continue;
}
let bone = boneInfos[boneNode._boneIndex];
// Bone has been destroy
if (!bone) {
boneNode.removeFromParent(true);
boneNode.destroy();
nodeArray[i] = null;
nodeArrayDirty = true;
continue;
}
matrixHandle(boneNode._worldMatrix, rootNode._worldMatrix, bone);
boneNode._renderFlag &= ~FLAG_TRANSFORM;
}
if (nodeArrayDirty) {
this._rebuildNodeArray();
}
},
});
module.exports = sp.AttachUtil = AttachUtil;

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,259 @@
/****************************************************************************
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.
****************************************************************************/
'use strict';
/*
* Reference:
* http://en.esotericsoftware.com/spine-json-format
*/
const Fs = require('fire-fs');
const Path = require('fire-path');
const Spine = require('../lib/spine');
const ATLAS_EXTS = ['.atlas', '.txt', '.atlas.txt', ''];
const SPINE_ENCODING = { encoding: 'utf-8' };
const CustomAssetMeta = Editor.metas['custom-asset'];
function searchAtlas (skeletonPath, callback) {
skeletonPath = Path.stripExt(skeletonPath);
function next (index) {
var suffix = ATLAS_EXTS[index];
var path = skeletonPath + suffix;
Fs.exists(path, exists => {
if (exists) {
return callback(null, path);
}
else if (index + 1 < ATLAS_EXTS.length) {
next(index + 1);
}
else {
callback(new Error(`Can not find ${skeletonPath + ATLAS_EXTS[0]}`));
}
});
}
next(0);
}
function loadAtlasText (skeletonPath, callback) {
searchAtlas(skeletonPath, (err, path) => {
if (err) {
return callback(err);
}
Fs.readFile(path, SPINE_ENCODING, (err, data) => {
callback(err, {
data: data,
atlasPath: path
});
});
});
}
// A dummy texture loader to record all textures in atlas
class TextureParser {
constructor (atlasPath) {
this.atlasPath = atlasPath;
// array of loaded texture uuid
this.textures = [];
// array of corresponding line
this.textureNames = [];
}
load (line) {
var name = Path.basename(line);
var base = Path.dirname(this.atlasPath);
var path = Path.resolve(base, name);
var uuid = Editor.assetdb.fspathToUuid(path);
if (uuid) {
console.log('UUID is initialized for "%s".', path);
this.textures.push(uuid);
this.textureNames.push(line);
var tex = new Spine.Texture({});
tex.setFilters = function() {};
tex.setWraps = function() {};
return tex;
}
else if (!Fs.existsSync(path)) {
Editor.error('Can not find texture "%s" for atlas "%s"', line, this.atlasPath);
}
else {
// AssetDB may call postImport more than once, we can get uuid in the next time.
console.warn('WARN: UUID not yet initialized for "%s".', path);
}
return null;
}
}
class SpineMeta extends CustomAssetMeta {
constructor (assetdb) {
super(assetdb);
this.textures = [];
this.scale = 1;
}
dests () {
let rawPath = this._assetdb.uuidToFspath(this.uuid);
let importPathNoExt = this._assetdb._uuidToImportPathNoExt(this.uuid);
let jsonPath = importPathNoExt + '.json';
let extname = Path.extname(rawPath);
let nativePath = importPathNoExt + extname;
return [jsonPath, nativePath];
}
// HACK - for inspector
get texture () {
return Editor.assetdb.uuidToUrl(this.textures[0]);
}
set texture (value) {
this.textures[0] = Editor.assetdb.urlToUuid(value);
}
static version () { return '1.2.5'; }
static defaultType () {
return 'spine';
}
static validate (assetpath) {
// handle binary file
if (assetpath.endsWith(".skel")) {
return true;
}
// TODO - import as a folder named '***.spine'
var json;
var text = Fs.readFileSync(assetpath, 'utf8');
var fastTest = text.slice(0, 30);
var maybe = ( fastTest.indexOf('slots') > 0 ||
fastTest.indexOf('skins') > 0 ||
fastTest.indexOf('events') > 0 ||
fastTest.indexOf('animations') > 0 ||
fastTest.indexOf('bones') > 0 ||
fastTest.indexOf('skeleton') > 0 ||
fastTest.indexOf('\"ik\"') > 0
);
if (maybe) {
try {
json = JSON.parse(text);
}
catch (e) {
return false;
}
return Array.isArray(json.bones);
}
return false;
}
_initTexture (asset, fspath, cb) {
loadAtlasText(fspath, (err, res) => {
if (err) {
return cb(err);
}
var db = this._assetdb;
// parse atlas textures
var textureParser = new TextureParser(res.atlasPath);
try {
new Spine.TextureAtlas(res.data, textureParser.load.bind(textureParser));
}
catch (err) {
return cb(new Error(`Failed to load atlas file: "${res.atlasPath}". ${err.stack || err}`));
}
this.textures = textureParser.textures;
asset.textures = textureParser.textures.map(Editor.serialize.asAsset);
asset.textureNames = textureParser.textureNames;
asset.atlasText = res.data;
db.saveAssetToLibrary(this.uuid, asset);
cb();
});
}
_importJson (fspath, cb) {
Fs.readFile(fspath, SPINE_ENCODING, (err, data) => {
if (err) {
return cb(err);
}
var json;
try {
json = JSON.parse(data);
}
catch (e) {
return cb(e);
}
var asset = new sp.SkeletonData();
asset.name = Path.basenameNoExt(fspath);
asset.skeletonJson = json;
asset.scale = this.scale;
this._initTexture(asset, fspath, cb);
});
}
_importBinary (fspath, cb) {
// import native asset
// Since skel is not in the white list of the WeChat suffix, bin is used instead
let extname = ".bin";
let dest = this._assetdb._uuidToImportPathNoExt(this.uuid) + extname;
Fs.copy(fspath, dest, err => {
if (err) {
return cb(err);
}
// import asset
let asset = new sp.SkeletonData();
asset.name = Path.basenameNoExt(fspath);
asset._setRawAsset(extname);
asset.scale = this.scale;
this._initTexture(asset, fspath, cb);
});
}
import (fspath, cb) {
if (fspath.endsWith(".skel")) {
this._importBinary(fspath, cb);
} else {
super.import(fspath, cb);
}
}
postImport (fspath, cb) {
if (!fspath.endsWith(".skel")) {
this._importJson(fspath, cb);
} else {
cb();
}
}
}
module.exports = SpineMeta;

View File

@@ -0,0 +1,153 @@
/****************************************************************************
Copyright (c) 2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
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
* The global main namespace of Spine, all classes, functions,
* properties and constants of Spine are defined in this namespace
* !#zh
* Spine 的全局的命名空间,
* 与 Spine 相关的所有的类,函数,属性,常量都在这个命名空间中定义。
* @module sp
* @main sp
*/
/*
* Reference:
* http://esotericsoftware.com/spine-runtime-terminology
* http://esotericsoftware.com/files/runtime-diagram.png
* http://en.esotericsoftware.com/spine-using-runtimes
*/
var _global = typeof window === 'undefined' ? global : window;
var _isUseSpine = true;
if (!CC_NATIVERENDERER) {
_global.spine = require('./lib/spine');
} else if (!_global.spine) {
_isUseSpine = false;
}
if (_isUseSpine) {
_global.sp = _global.sp || {};
/**
* !#en
* The global time scale of Spine.
* !#zh
* Spine 全局时间缩放率。
* @example
* sp.timeScale = 0.8;
*/
sp._timeScale = 1.0;
Object.defineProperty(sp, 'timeScale', {
get () {
return this._timeScale;
},
set (value) {
this._timeScale = value;
},
configurable: true,
});
// The attachment type of spine. It contains three type: REGION(0), BOUNDING_BOX(1), MESH(2) and SKINNED_MESH.
sp.ATTACHMENT_TYPE = {
REGION: 0,
BOUNDING_BOX: 1,
MESH: 2,
SKINNED_MESH:3
};
/**
* !#en The event type of spine skeleton animation.
* !#zh 骨骼动画事件类型。
* @enum AnimationEventType
*/
sp.AnimationEventType = cc.Enum({
/**
* !#en The play spine skeleton animation start type.
* !#zh 开始播放骨骼动画。
* @property {Number} START
*/
START: 0,
/**
* !#en Another entry has replaced this entry as the current entry. This entry may continue being applied for mixing.
* !#zh 当前的 entry 被其他的 entry 替换。当使用 mixing 时,当前的 entry 会继续运行。
*/
INTERRUPT: 1,
/**
* !#en The play spine skeleton animation finish type.
* !#zh 播放骨骼动画结束。
* @property {Number} END
*/
END: 2,
/**
* !#en The entry will be disposed.
* !#zh entry 将被销毁。
*/
DISPOSE: 3,
/**
* !#en The play spine skeleton animation complete type.
* !#zh 播放骨骼动画完成。
* @property {Number} COMPLETE
*/
COMPLETE: 4,
/**
* !#en The spine skeleton animation event type.
* !#zh 骨骼动画事件。
* @property {Number} EVENT
*/
EVENT: 5
});
/**
* @module sp
*/
if (!CC_EDITOR || !Editor.isMainProcess) {
sp.spine = _global.spine;
if (!CC_NATIVERENDERER) {
require('./skeleton-texture');
}
require('./skeleton-data');
require('./vertex-effect-delegate');
require('./Skeleton');
require('./spine-assembler');
}
else {
require('./skeleton-data');
}
}
/**
* !#en
* `sp.spine` is the namespace for official Spine Runtime, which officially implemented and maintained by Spine.<br>
* Please refer to the official documentation for its detailed usage: [http://en.esotericsoftware.com/spine-using-runtimes](http://en.esotericsoftware.com/spine-using-runtimes)
* !#zh
* sp.spine 模块是 Spine 官方运行库的 API 入口,由 Spine 官方统一实现和维护,具体用法请参考:[http://zh.esotericsoftware.com/spine-using-runtimes](http://zh.esotericsoftware.com/spine-using-runtimes)
* @module sp.spine
* @main sp.spine
*/

View File

@@ -0,0 +1,27 @@
Spine Runtimes Software License v2.5
Copyright (c) 2013-2016, Esoteric Software
All rights reserved.
You are granted a perpetual, non-exclusive, non-sublicensable, and
non-transferable license to use, install, execute, and perform the Spine
Runtimes software and derivative works solely for personal or internal
use. Without the written permission of Esoteric Software (see Section 2 of
the Spine Software License Agreement), you may not (a) modify, translate,
adapt, or develop new applications using the Spine Runtimes or otherwise
create derivative works or improvements of the Spine Runtimes or (b) remove,
delete, alter, or obscure any trademarks or any copyright, trademark, patent,
or other intellectual property or proprietary rights notices on or in the
Software, including any copy thereof. Redistributions in binary or source
form must include this license and terms.
THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

1331
engine/extensions/spine/lib/spine.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,648 @@
/****************************************************************************
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.
****************************************************************************/
const TrackEntryListeners = require('./track-entry-listeners');
const spine = require('./lib/spine');
// Permit max cache time, unit is second.
const MaxCacheTime = 30;
const FrameTime = 1 / 60;
let _vertices = [];
let _indices = [];
let _boneInfoOffset = 0;
let _vertexOffset = 0;
let _indexOffset = 0;
let _vfOffset = 0;
let _preTexUrl = null;
let _preBlendMode = null;
let _segVCount = 0;
let _segICount = 0;
let _segOffset = 0;
let _colorOffset = 0;
let _preFinalColor = null;
let _preDarkColor = null;
// x y u v c1 c2
let _perVertexSize = 6;
// x y u v r1 g1 b1 a1 r2 g2 b2 a2
let _perClipVertexSize = 12;
let _vfCount = 0, _indexCount = 0;
let _tempr, _tempg, _tempb, _tempa;
let _finalColor32, _darkColor32;
let _finalColor = new spine.Color(1, 1, 1, 1);
let _darkColor = new spine.Color(1, 1, 1, 1);
let _quadTriangles = [0, 1, 2, 2, 3, 0];
//Cache all frames in an animation
let AnimationCache = cc.Class({
ctor () {
this._privateMode = false;
this._inited = false;
this._invalid = true;
this._enableCacheAttachedInfo = false;
this.frames = [];
this.totalTime = 0;
this._frameIdx = -1;
this.isCompleted = false;
this._skeletonInfo = null;
this._animationName = null;
this._tempSegments = null;
this._tempColors = null;
this._tempBoneInfos = null;
},
init (skeletonInfo, animationName) {
this._inited = true;
this._animationName = animationName;
this._skeletonInfo = skeletonInfo;
},
// Clear texture quote.
clear () {
this._inited = false;
for (let i = 0, n = this.frames.length; i < n; i++) {
let frame = this.frames[i];
frame.segments.length = 0;
}
this.invalidAllFrame();
},
bind (listener) {
let completeHandle = function (entry) {
if (entry && entry.animation.name === this._animationName) {
this.isCompleted = true;
}
}.bind(this);
listener.complete = completeHandle;
},
unbind (listener) {
listener.complete = null;
},
begin () {
if (!this._invalid) return;
let skeletonInfo = this._skeletonInfo;
let preAnimationCache = skeletonInfo.curAnimationCache;
if (preAnimationCache && preAnimationCache !== this) {
if (this._privateMode) {
// Private cache mode just invalid pre animation frame.
preAnimationCache.invalidAllFrame();
} else {
// If pre animation not finished, play it to the end.
preAnimationCache.updateToFrame();
}
}
let skeleton = skeletonInfo.skeleton;
let listener = skeletonInfo.listener;
let state = skeletonInfo.state;
let animation = skeleton.data.findAnimation(this._animationName);
state.setAnimationWith(0, animation, false);
this.bind(listener);
// record cur animation cache
skeletonInfo.curAnimationCache = this;
this._frameIdx = -1;
this.isCompleted = false;
this.totalTime = 0;
this._invalid = false;
},
end () {
if (!this._needToUpdate()) {
// clear cur animation cache
this._skeletonInfo.curAnimationCache = null;
this.frames.length = this._frameIdx + 1;
this.isCompleted = true;
this.unbind(this._skeletonInfo.listener);
}
},
_needToUpdate (toFrameIdx) {
return !this.isCompleted &&
this.totalTime < MaxCacheTime &&
(toFrameIdx == undefined || this._frameIdx < toFrameIdx);
},
updateToFrame (toFrameIdx) {
if (!this._inited) return;
this.begin();
if (!this._needToUpdate(toFrameIdx)) return;
let skeletonInfo = this._skeletonInfo;
let skeleton = skeletonInfo.skeleton;
let clipper = skeletonInfo.clipper;
let state = skeletonInfo.state;
do {
// Solid update frame rate 1/60.
skeleton.update(FrameTime);
state.update(FrameTime);
state.apply(skeleton);
skeleton.updateWorldTransform();
this._frameIdx++;
this._updateFrame(skeleton, clipper, this._frameIdx);
this.totalTime += FrameTime;
} while (this._needToUpdate(toFrameIdx));
this.end();
},
isInited () {
return this._inited;
},
isInvalid () {
return this._invalid;
},
invalidAllFrame () {
this.isCompleted = false;
this._invalid = true;
},
updateAllFrame () {
this.invalidAllFrame();
this.updateToFrame();
},
enableCacheAttachedInfo () {
if (!this._enableCacheAttachedInfo) {
this._enableCacheAttachedInfo = true;
this.invalidAllFrame();
}
},
_updateFrame (skeleton, clipper, index) {
_vfOffset = 0;
_boneInfoOffset = 0;
_indexOffset = 0;
_vertexOffset = 0;
_preTexUrl = null;
_preBlendMode = null;
_segVCount = 0;
_segICount = 0;
_segOffset = 0;
_colorOffset = 0;
_preFinalColor = null;
_preDarkColor = null;
this.frames[index] = this.frames[index] || {
segments : [],
colors : [],
boneInfos : [],
vertices : null,
uintVert : null,
indices : null,
};
let frame = this.frames[index];
let segments = this._tempSegments = frame.segments;
let colors = this._tempColors = frame.colors;
let boneInfos = this._tempBoneInfos = frame.boneInfos;
this._traverseSkeleton(skeleton, clipper);
if (_colorOffset > 0) {
colors[_colorOffset - 1].vfOffset = _vfOffset;
}
colors.length = _colorOffset;
boneInfos.length = _boneInfoOffset;
// Handle pre segment.
let preSegOffset = _segOffset - 1;
if (preSegOffset >= 0) {
// Judge segment vertex count is not empty.
if (_segICount > 0) {
let preSegInfo = segments[preSegOffset];
preSegInfo.indexCount = _segICount;
preSegInfo.vfCount = _segVCount * _perVertexSize;
preSegInfo.vertexCount = _segVCount;
segments.length = _segOffset;
} else {
// Discard pre segment.
segments.length = _segOffset - 1;
}
}
// Segments is empty,discard all segments.
if (segments.length == 0) return;
// Fill vertices
let vertices = frame.vertices;
let uintVert = frame.uintVert;
if (!vertices || vertices.length < _vfOffset) {
vertices = frame.vertices = new Float32Array(_vfOffset);
uintVert = frame.uintVert = new Uint32Array(vertices.buffer);
}
for (let i = 0, j = 0; i < _vfOffset;) {
vertices[i++] = _vertices[j++]; // x
vertices[i++] = _vertices[j++]; // y
vertices[i++] = _vertices[j++]; // u
vertices[i++] = _vertices[j++]; // v
uintVert[i++] = _vertices[j++]; // color1
uintVert[i++] = _vertices[j++]; // color2
}
// Fill indices
let indices = frame.indices;
if (!indices || indices.length < _indexOffset) {
indices = frame.indices = new Uint16Array(_indexOffset);
}
for (let i = 0; i < _indexOffset; i++) {
indices[i] = _indices[i];
}
frame.vertices = vertices;
frame.uintVert = uintVert;
frame.indices = indices;
},
fillVertices (skeletonColor, attachmentColor, slotColor, clipper, slot) {
_tempa = slotColor.a * attachmentColor.a * skeletonColor.a * 255;
_tempr = attachmentColor.r * skeletonColor.r * 255;
_tempg = attachmentColor.g * skeletonColor.g * 255;
_tempb = attachmentColor.b * skeletonColor.b * 255;
_finalColor.r = _tempr * slotColor.r;
_finalColor.g = _tempg * slotColor.g;
_finalColor.b = _tempb * slotColor.b;
_finalColor.a = _tempa;
if (slot.darkColor == null) {
_darkColor.set(0.0, 0, 0, 1.0);
} else {
_darkColor.r = slot.darkColor.r * _tempr;
_darkColor.g = slot.darkColor.g * _tempg;
_darkColor.b = slot.darkColor.b * _tempb;
}
_darkColor.a = 0;
_finalColor32 = ((_finalColor.a<<24) >>> 0) + (_finalColor.b<<16) + (_finalColor.g<<8) + _finalColor.r;
_darkColor32 = ((_darkColor.a<<24) >>> 0) + (_darkColor.b<<16) + (_darkColor.g<<8) + _darkColor.r;
if (_preFinalColor !== _finalColor32 || _preDarkColor !== _darkColor32) {
let colors = this._tempColors;
_preFinalColor = _finalColor32;
_preDarkColor = _darkColor32;
if (_colorOffset > 0) {
colors[_colorOffset - 1].vfOffset = _vfOffset;
}
colors[_colorOffset++] = {
fr : _finalColor.r,
fg : _finalColor.g,
fb : _finalColor.b,
fa : _finalColor.a,
dr : _darkColor.r,
dg : _darkColor.g,
db : _darkColor.b,
da : _darkColor.a,
vfOffset : 0
}
}
if (!clipper.isClipping()) {
for (let v = _vfOffset, n = _vfOffset + _vfCount; v < n; v += _perVertexSize) {
_vertices[v + 4] = _finalColor32; // light color
_vertices[v + 5] = _darkColor32; // dark color
}
} else {
clipper.clipTriangles(_vertices, _vfCount, _indices, _indexCount, _vertices, _finalColor, _darkColor, true, _perVertexSize, _indexOffset, _vfOffset, _vfOffset + 2);
let clippedVertices = clipper.clippedVertices;
let clippedTriangles = clipper.clippedTriangles;
// insure capacity
_indexCount = clippedTriangles.length;
_vfCount = clippedVertices.length / _perClipVertexSize * _perVertexSize;
// fill indices
for (let ii = 0, jj = _indexOffset, nn = clippedTriangles.length; ii < nn;) {
_indices[jj++] = clippedTriangles[ii++];
}
// fill vertices contain x y u v light color dark color
for (let v = 0, n = clippedVertices.length, offset = _vfOffset; v < n; v += 12, offset += _perVertexSize) {
_vertices[offset] = clippedVertices[v]; // x
_vertices[offset + 1] = clippedVertices[v + 1]; // y
_vertices[offset + 2] = clippedVertices[v + 6]; // u
_vertices[offset + 3] = clippedVertices[v + 7]; // v
_vertices[offset + 4] = _finalColor32;
_vertices[offset + 5] = _darkColor32;
}
}
},
_traverseSkeleton (skeleton, clipper) {
let segments = this._tempSegments;
let boneInfos = this._tempBoneInfos;
let skeletonColor = skeleton.color;
let attachment, attachmentColor, slotColor, uvs, triangles;
let isRegion, isMesh, isClip;
let texture;
let preSegOffset, preSegInfo;
let blendMode;
let slot;
let bones = skeleton.bones;
if (this._enableCacheAttachedInfo) {
for (let i = 0, l = bones.length; i < l; i++, _boneInfoOffset++) {
let bone = bones[i];
let boneInfo = boneInfos[_boneInfoOffset];
if (!boneInfo) {
boneInfo = boneInfos[_boneInfoOffset] = {};
}
boneInfo.a = bone.a;
boneInfo.b = bone.b;
boneInfo.c = bone.c;
boneInfo.d = bone.d;
boneInfo.worldX = bone.worldX;
boneInfo.worldY = bone.worldY;
}
}
for (let slotIdx = 0, slotCount = skeleton.drawOrder.length; slotIdx < slotCount; slotIdx++) {
slot = skeleton.drawOrder[slotIdx];
if(!slot.bone.active) {
continue;
}
_vfCount = 0;
_indexCount = 0;
attachment = slot.getAttachment();
if (!attachment) {
clipper.clipEndWithSlot(slot);
continue;
}
isRegion = attachment instanceof spine.RegionAttachment;
isMesh = attachment instanceof spine.MeshAttachment;
isClip = attachment instanceof spine.ClippingAttachment;
if (isClip) {
clipper.clipStart(slot, attachment);
continue;
}
if (!isRegion && !isMesh) {
clipper.clipEndWithSlot(slot);
continue;
}
texture = attachment.region.texture._texture;
if (!texture) {
clipper.clipEndWithSlot(slot);
continue;
}
blendMode = slot.data.blendMode;
if (_preTexUrl !== texture.nativeUrl || _preBlendMode !== blendMode) {
_preTexUrl = texture.nativeUrl;
_preBlendMode = blendMode;
// Handle pre segment.
preSegOffset = _segOffset - 1;
if (preSegOffset >= 0) {
if (_segICount > 0) {
preSegInfo = segments[preSegOffset];
preSegInfo.indexCount = _segICount;
preSegInfo.vertexCount = _segVCount;
preSegInfo.vfCount = _segVCount * _perVertexSize;
} else {
// Discard pre segment.
_segOffset--;
}
}
// Handle now segment.
segments[_segOffset] = {
tex : texture,
blendMode : blendMode,
indexCount : 0,
vertexCount : 0,
vfCount : 0
};
_segOffset++;
_segICount = 0;
_segVCount = 0;
}
if (isRegion) {
triangles = _quadTriangles;
// insure capacity
_vfCount = 4 * _perVertexSize;
_indexCount = 6;
// compute vertex and fill x y
attachment.computeWorldVertices(slot.bone, _vertices, _vfOffset, _perVertexSize);
}
else if (isMesh) {
triangles = attachment.triangles;
// insure capacity
_vfCount = (attachment.worldVerticesLength >> 1) * _perVertexSize;
_indexCount = triangles.length;
// compute vertex and fill x y
attachment.computeWorldVertices(slot, 0, attachment.worldVerticesLength, _vertices, _vfOffset, _perVertexSize);
}
if (_vfCount == 0 || _indexCount == 0) {
clipper.clipEndWithSlot(slot);
continue;
}
// fill indices
for (let ii = 0, jj = _indexOffset, nn = triangles.length; ii < nn;) {
_indices[jj++] = triangles[ii++];
}
// fill u v
uvs = attachment.uvs;
for (let v = _vfOffset, n = _vfOffset + _vfCount, u = 0; v < n; v += _perVertexSize, u += 2) {
_vertices[v + 2] = uvs[u]; // u
_vertices[v + 3] = uvs[u + 1]; // v
}
attachmentColor = attachment.color;
slotColor = slot.color;
this.fillVertices(skeletonColor, attachmentColor, slotColor, clipper, slot);
if (_indexCount > 0) {
for (let ii = _indexOffset, nn = _indexOffset + _indexCount; ii < nn; ii++) {
_indices[ii] += _segVCount;
}
_indexOffset += _indexCount;
_vfOffset += _vfCount;
_vertexOffset = _vfOffset / _perVertexSize;
_segICount += _indexCount;
_segVCount += _vfCount / _perVertexSize;
}
clipper.clipEndWithSlot(slot);
}
clipper.clipEnd();
}
});
let SkeletonCache = cc.Class({
ctor () {
this._privateMode = false;
this._animationPool = {};
this._skeletonCache = {};
},
enablePrivateMode () {
this._privateMode = true;
},
clear () {
this._animationPool = {};
this._skeletonCache = {};
},
removeSkeleton (uuid) {
var skeletonInfo = this._skeletonCache[uuid];
if (!skeletonInfo) return;
let animationsCache = skeletonInfo.animationsCache;
for (var aniKey in animationsCache) {
// Clear cache texture, and put cache into pool.
// No need to create TypedArray next time.
let animationCache = animationsCache[aniKey];
if (!animationCache) continue;
this._animationPool[uuid + "#" + aniKey] = animationCache;
animationCache.clear();
}
delete this._skeletonCache[uuid];
},
getSkeletonCache (uuid, skeletonData) {
let skeletonInfo = this._skeletonCache[uuid];
if (!skeletonInfo) {
let skeleton = new spine.Skeleton(skeletonData);
let clipper = new spine.SkeletonClipping();
let stateData = new spine.AnimationStateData(skeleton.data);
let state = new spine.AnimationState(stateData);
let listener = new TrackEntryListeners();
state.addListener(listener);
this._skeletonCache[uuid] = skeletonInfo = {
skeleton : skeleton,
clipper : clipper,
state : state,
listener : listener,
// Cache all kinds of animation frame.
// When skeleton is dispose, clear all animation cache.
animationsCache : {},
curAnimationCache: null
};
}
return skeletonInfo;
},
getAnimationCache (uuid, animationName) {
let skeletonInfo = this._skeletonCache[uuid];
if (!skeletonInfo) return null;
let animationsCache = skeletonInfo.animationsCache;
return animationsCache[animationName];
},
invalidAnimationCache (uuid) {
let skeletonInfo = this._skeletonCache[uuid];
let skeleton = skeletonInfo && skeletonInfo.skeleton;
if (!skeleton) return;
let animationsCache = skeletonInfo.animationsCache;
for (var aniKey in animationsCache) {
let animationCache = animationsCache[aniKey];
animationCache.invalidAllFrame();
}
},
initAnimationCache (uuid, animationName) {
if (!animationName) return null;
let skeletonInfo = this._skeletonCache[uuid];
let skeleton = skeletonInfo && skeletonInfo.skeleton;
if (!skeleton) return null;
let animation = skeleton.data.findAnimation(animationName);
if (!animation) {
return null;
}
let animationsCache = skeletonInfo.animationsCache;
let animationCache = animationsCache[animationName];
if (!animationCache) {
// If cache exist in pool, then just use it.
let poolKey = uuid + "#" + animationName;
animationCache = this._animationPool[poolKey];
if (animationCache) {
delete this._animationPool[poolKey];
} else {
animationCache = new AnimationCache();
animationCache._privateMode = this._privateMode;
}
animationCache.init(skeletonInfo, animationName);
animationsCache[animationName] = animationCache;
}
return animationCache;
},
updateAnimationCache (uuid, animationName) {
if (animationName) {
let animationCache = this.initAnimationCache(uuid, animationName);
if (!animationCache) return null;
animationCache.updateAllFrame();
} else {
let skeletonInfo = this._skeletonCache[uuid];
let skeleton = skeletonInfo && skeletonInfo.skeleton;
if (!skeleton) return;
let animationsCache = skeletonInfo.animationsCache;
for (var aniKey in animationsCache) {
let animationCache = animationsCache[aniKey];
animationCache.updateAllFrame();
}
}
}
});
SkeletonCache.FrameTime = FrameTime;
SkeletonCache.sharedCache = new SkeletonCache();
module.exports = SkeletonCache;

View File

@@ -0,0 +1,331 @@
/****************************************************************************
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.
****************************************************************************/
/**
* @module sp
*/
let SkeletonCache = !CC_JSB && require('./skeleton-cache').sharedCache;
/**
* !#en The skeleton data of spine.
* !#zh Spine 的 骨骼数据。
* @class SkeletonData
* @extends Asset
*/
let SkeletonData = cc.Class({
name: 'sp.SkeletonData',
extends: cc.Asset,
ctor: function () {
this.reset();
},
properties: {
_skeletonJson: null,
// use by jsb
skeletonJsonStr: {
get: function () {
if (this._skeletonJson) {
return JSON.stringify(this._skeletonJson);
} else {
return "";
}
}
},
/**
* !#en See http://en.esotericsoftware.com/spine-json-format
* !#zh 可查看 Spine 官方文档 http://zh.esotericsoftware.com/spine-json-format
* @property {Object} skeletonJson
*/
skeletonJson: {
get: function () {
return this._skeletonJson;
},
set: function (value) {
this.reset();
if (typeof(value) == "string") {
this._skeletonJson = JSON.parse(value);
} else {
this._skeletonJson = value;
}
// If create by manual, uuid is empty.
if (!this._uuid && value.skeleton) {
this._uuid = value.skeleton.hash;
}
}
},
_atlasText: "",
/**
* @property {String} atlasText
*/
atlasText: {
get: function () {
return this._atlasText;
},
set: function (value) {
this._atlasText = value;
this.reset();
}
},
/**
* @property {Texture2D[]} textures
*/
textures: {
default: [],
type: [cc.Texture2D]
},
/**
* @property {String[]} textureNames
* @private
*/
textureNames: {
default: [],
type: [cc.String]
},
/**
* !#en
* A scale can be specified on the JSON or binary loader which will scale the bone positions,
* image sizes, and animation translations.
* This can be useful when using different sized images than were used when designing the skeleton
* in Spine. For example, if using images that are half the size than were used in Spine,
* a scale of 0.5 can be used. This is commonly used for games that can run with either low or high
* resolution texture atlases.
* see http://en.esotericsoftware.com/spine-using-runtimes#Scaling
* !#zh 可查看 Spine 官方文档: http://zh.esotericsoftware.com/spine-using-runtimes#Scaling
* @property {Number} scale
*/
scale: 1,
_nativeAsset: {
get () {
return this._buffer;
},
set (bin) {
this._buffer = bin.buffer || bin;
this.reset();
},
override: true
},
},
statics: {
preventDeferredLoadDependents: true,
},
// PUBLIC
createNode: CC_EDITOR && function (callback) {
let node = new cc.Node(this.name);
let skeleton = node.addComponent(sp.Skeleton);
skeleton.skeletonData = this;
return callback(null, node);
},
reset: function () {
/**
* @property {sp.spine.SkeletonData} _skeletonData
* @private
*/
this._skeletonCache = null;
/**
* @property {sp.spine.Atlas} _atlasCache
* @private
*/
this._atlasCache = null;
if (CC_EDITOR) {
this._skinsEnum = null;
this._animsEnum = null;
}
},
ensureTexturesLoaded (loaded, caller) {
let textures = this.textures;
let texsLen = textures.length;
if (texsLen == 0) {
loaded.call(caller, false);
return;
}
let loadedCount = 0;
let loadedItem = function () {
loadedCount++;
if (loadedCount >= texsLen) {
loaded && loaded.call(caller, true);
loaded = null;
}
}
for (let i = 0; i < texsLen; i++) {
let tex = textures[i];
if (tex.loaded) {
loadedItem();
} else {
tex.once('load', loadedItem);
}
}
},
isTexturesLoaded () {
let textures = this.textures;
let texsLen = textures.length;
for (let i = 0; i < texsLen; i++) {
let tex = textures[i];
if (!tex.loaded) {
return false;
}
}
return true;
},
/**
* !#en Get the included SkeletonData used in spine runtime.<br>
* Returns a {{#crossLinkModule "sp.spine"}}sp.spine{{/crossLinkModule}}.SkeletonData object.
* !#zh 获取 Spine Runtime 使用的 SkeletonData。<br>
* 返回一个 {{#crossLinkModule "sp.spine"}}sp.spine{{/crossLinkModule}}.SkeletonData 对象。
* @method getRuntimeData
* @param {Boolean} [quiet=false]
* @return {sp.spine.SkeletonData}
*/
getRuntimeData: function (quiet) {
if (this._skeletonCache) {
return this._skeletonCache;
}
if ( !(this.textures && this.textures.length > 0) && this.textureNames && this.textureNames.length > 0 ) {
if ( !quiet ) {
cc.errorID(7507, this.name);
}
return null;
}
let atlas = this._getAtlas(quiet);
if (! atlas) {
return null;
}
let attachmentLoader = new sp.spine.AtlasAttachmentLoader(atlas);
let resData = null;
let reader = null;
if (this.skeletonJson) {
reader = new sp.spine.SkeletonJson(attachmentLoader);
resData = this.skeletonJson;
} else {
reader = new sp.spine.SkeletonBinary(attachmentLoader);
resData = new Uint8Array(this._nativeAsset);
}
reader.scale = this.scale;
this._skeletonCache = reader.readSkeletonData(resData);
atlas.dispose();
return this._skeletonCache;
},
// EDITOR
getSkinsEnum: CC_EDITOR && function () {
if (this._skinsEnum) {
return this._skinsEnum;
}
let sd = this.getRuntimeData(true);
if (sd) {
let skins = sd.skins;
let enumDef = {};
for (let i = 0; i < skins.length; i++) {
let name = skins[i].name;
enumDef[name] = i;
}
return this._skinsEnum = cc.Enum(enumDef);
}
return null;
},
getAnimsEnum: CC_EDITOR && function () {
if (this._animsEnum) {
return this._animsEnum;
}
let sd = this.getRuntimeData(true);
if (sd) {
let enumDef = { '<None>': 0 };
let anims = sd.animations;
for (let i = 0; i < anims.length; i++) {
let name = anims[i].name;
enumDef[name] = i + 1;
}
return this._animsEnum = cc.Enum(enumDef);
}
return null;
},
// PRIVATE
_getTexture: function (line) {
let names = this.textureNames;
for (let i = 0; i < names.length; i++) {
if (names[i] === line) {
let texture = this.textures[i];
let tex = new sp.SkeletonTexture({ width: texture.width, height: texture.height });
tex.setRealTexture(texture);
return tex;
}
}
cc.errorID(7506, line);
return null;
},
/**
* @method _getAtlas
* @param {boolean} [quiet=false]
* @return {sp.spine.Atlas}
* @private
*/
_getAtlas: function (quiet) {
if (this._atlasCache) {
return this._atlasCache;
}
if ( !this.atlasText ) {
if ( !quiet ) {
cc.errorID(7508, this.name);
}
return null;
}
return this._atlasCache = new sp.spine.TextureAtlas(this.atlasText, this._getTexture.bind(this));
},
destroy () {
SkeletonCache.removeSkeleton(this._uuid);
this._super();
},
});
sp.SkeletonData = module.exports = SkeletonData;

View File

@@ -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.
****************************************************************************/
sp.SkeletonTexture = cc.Class({
name: 'sp.SkeletonTexture',
extends: sp.spine.Texture,
_texture: null,
_material: null,
setRealTexture: function(tex) {
this._texture = tex;
},
getRealTexture: function() {
return this._texture;
},
setFilters: function(minFilter, magFilter) {
if (this._texture) {
this._texture.setFilters(minFilter, magFilter);
}
},
setWraps: function(uWrap, vWrap) {
if (this._texture) {
this._texture.setWrapMode(uWrap, vWrap);
}
},
dispose: function() {}
});

View File

@@ -0,0 +1,689 @@
/****************************************************************************
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 Assembler from '../../cocos2d/core/renderer/assembler';
const Skeleton = require('./Skeleton');
const spine = require('./lib/spine');
const RenderFlow = require('../../cocos2d/core/renderer/render-flow');
const VertexFormat = require('../../cocos2d/core/renderer/webgl/vertex-format')
const VFOneColor = VertexFormat.vfmtPosUvColor;
const VFTwoColor = VertexFormat.vfmtPosUvTwoColor;
const gfx = cc.gfx;
const FLAG_BATCH = 0x10;
const FLAG_TWO_COLOR = 0x01;
let _handleVal = 0x00;
let _quadTriangles = [0, 1, 2, 2, 3, 0];
let _slotColor = cc.color(0, 0, 255, 255);
let _boneColor = cc.color(255, 0, 0, 255);
let _originColor = cc.color(0, 255, 0, 255);
let _meshColor = cc.color(255, 255, 0, 255);
let _finalColor = null;
let _darkColor = null;
let _tempPos = null, _tempUv = null;
if (!CC_NATIVERENDERER) {
_finalColor = new spine.Color(1, 1, 1, 1);
_darkColor = new spine.Color(1, 1, 1, 1);
_tempPos = new spine.Vector2();
_tempUv = new spine.Vector2();
}
let _premultipliedAlpha;
let _multiplier;
let _slotRangeStart;
let _slotRangeEnd;
let _useTint;
let _debugSlots;
let _debugBones;
let _debugMesh;
let _nodeR,
_nodeG,
_nodeB,
_nodeA;
let _finalColor32, _darkColor32;
let _vertexFormat;
let _perVertexSize;
let _perClipVertexSize;
let _vertexFloatCount = 0, _vertexCount = 0, _vertexFloatOffset = 0, _vertexOffset = 0,
_indexCount = 0, _indexOffset = 0, _vfOffset = 0;
let _tempr, _tempg, _tempb;
let _inRange;
let _mustFlush;
let _x, _y, _m00, _m04, _m12, _m01, _m05, _m13;
let _r, _g, _b, _fr, _fg, _fb, _fa, _dr, _dg, _db, _da;
let _comp, _buffer, _renderer, _node, _needColor, _vertexEffect;
function _getSlotMaterial (tex, blendMode) {
let src, dst;
switch (blendMode) {
case spine.BlendMode.Additive:
src = _premultipliedAlpha ? cc.macro.ONE : cc.macro.SRC_ALPHA;
dst = cc.macro.ONE;
break;
case spine.BlendMode.Multiply:
src = cc.macro.DST_COLOR;
dst = cc.macro.ONE_MINUS_SRC_ALPHA;
break;
case spine.BlendMode.Screen:
src = cc.macro.ONE;
dst = cc.macro.ONE_MINUS_SRC_COLOR;
break;
case spine.BlendMode.Normal:
default:
src = _premultipliedAlpha ? cc.macro.ONE : cc.macro.SRC_ALPHA;
dst = cc.macro.ONE_MINUS_SRC_ALPHA;
break;
}
let useModel = !_comp.enableBatch;
let baseMaterial = _comp._materials[0];
if (!baseMaterial) return null;
// The key use to find corresponding material
let key = tex.getId() + src + dst + _useTint + useModel;
let materialCache = _comp._materialCache;
let material = materialCache[key];
if (!material) {
if (!materialCache.baseMaterial) {
material = baseMaterial;
materialCache.baseMaterial = baseMaterial;
} else {
material = cc.MaterialVariant.create(baseMaterial);
}
material.define('CC_USE_MODEL', useModel);
material.define('USE_TINT', _useTint);
// update texture
material.setProperty('texture', tex);
// update blend function
material.setBlend(
true,
gfx.BLEND_FUNC_ADD,
src, dst,
gfx.BLEND_FUNC_ADD,
src, dst
);
materialCache[key] = material;
}
return material;
}
function _handleColor (color) {
// temp rgb has multiply 255, so need divide 255;
_fa = color.fa * _nodeA;
_multiplier = _premultipliedAlpha ? _fa / 255 : 1;
_r = _nodeR * _multiplier;
_g = _nodeG * _multiplier;
_b = _nodeB * _multiplier;
_fr = color.fr * _r;
_fg = color.fg * _g;
_fb = color.fb * _b;
_finalColor32 = ((_fa<<24) >>> 0) + (_fb<<16) + (_fg<<8) + _fr;
_dr = color.dr * _r;
_dg = color.dg * _g;
_db = color.db * _b;
_da = _premultipliedAlpha ? 255 : 0;
_darkColor32 = ((_da<<24) >>> 0) + (_db<<16) + (_dg<<8) + _dr;
}
function _spineColorToInt32 (spineColor) {
return ((spineColor.a<<24) >>> 0) + (spineColor.b<<16) + (spineColor.g<<8) + spineColor.r;
}
export default class SpineAssembler extends Assembler {
updateRenderData (comp) {
if (comp.isAnimationCached()) return;
let skeleton = comp._skeleton;
if (skeleton) {
skeleton.updateWorldTransform();
}
}
fillVertices (skeletonColor, attachmentColor, slotColor, clipper, slot) {
let vbuf = _buffer._vData,
ibuf = _buffer._iData,
uintVData = _buffer._uintVData;
let offsetInfo;
_finalColor.a = slotColor.a * attachmentColor.a * skeletonColor.a * _nodeA * 255;
_multiplier = _premultipliedAlpha? _finalColor.a : 255;
_tempr = _nodeR * attachmentColor.r * skeletonColor.r * _multiplier;
_tempg = _nodeG * attachmentColor.g * skeletonColor.g * _multiplier;
_tempb = _nodeB * attachmentColor.b * skeletonColor.b * _multiplier;
_finalColor.r = _tempr * slotColor.r;
_finalColor.g = _tempg * slotColor.g;
_finalColor.b = _tempb * slotColor.b;
if (slot.darkColor == null) {
_darkColor.set(0.0, 0.0, 0.0, 1.0);
} else {
_darkColor.r = slot.darkColor.r * _tempr;
_darkColor.g = slot.darkColor.g * _tempg;
_darkColor.b = slot.darkColor.b * _tempb;
}
_darkColor.a = _premultipliedAlpha ? 255 : 0;
if (!clipper.isClipping()) {
if (_vertexEffect) {
for (let v = _vertexFloatOffset, n = _vertexFloatOffset + _vertexFloatCount; v < n; v += _perVertexSize) {
_tempPos.x = vbuf[v];
_tempPos.y = vbuf[v + 1];
_tempUv.x = vbuf[v + 2];
_tempUv.y = vbuf[v + 3];
_vertexEffect.transform(_tempPos, _tempUv, _finalColor, _darkColor);
vbuf[v] = _tempPos.x; // x
vbuf[v + 1] = _tempPos.y; // y
vbuf[v + 2] = _tempUv.x; // u
vbuf[v + 3] = _tempUv.y; // v
uintVData[v + 4] = _spineColorToInt32(_finalColor); // light color
_useTint && (uintVData[v + 5] = _spineColorToInt32(_darkColor)); // dark color
}
} else {
_finalColor32 = _spineColorToInt32(_finalColor);
_darkColor32 = _spineColorToInt32(_darkColor);
for (let v = _vertexFloatOffset, n = _vertexFloatOffset + _vertexFloatCount; v < n; v += _perVertexSize) {
uintVData[v + 4] = _finalColor32; // light color
_useTint && (uintVData[v + 5] = _darkColor32); // dark color
}
}
} else {
let uvs = vbuf.subarray(_vertexFloatOffset + 2);
clipper.clipTriangles(vbuf.subarray(_vertexFloatOffset), _vertexFloatCount, ibuf.subarray(_indexOffset), _indexCount, uvs, _finalColor, _darkColor, _useTint, _perVertexSize);
let clippedVertices = new Float32Array(clipper.clippedVertices);
let clippedTriangles = clipper.clippedTriangles;
// insure capacity
_indexCount = clippedTriangles.length;
_vertexFloatCount = clippedVertices.length / _perClipVertexSize * _perVertexSize;
offsetInfo = _buffer.request(_vertexFloatCount / _perVertexSize, _indexCount);
_indexOffset = offsetInfo.indiceOffset,
_vertexOffset = offsetInfo.vertexOffset,
_vertexFloatOffset = offsetInfo.byteOffset >> 2;
vbuf = _buffer._vData,
ibuf = _buffer._iData;
uintVData = _buffer._uintVData;
// fill indices
ibuf.set(clippedTriangles, _indexOffset);
// fill vertices contain x y u v light color dark color
if (_vertexEffect) {
for (let v = 0, n = clippedVertices.length, offset = _vertexFloatOffset; v < n; v += _perClipVertexSize, offset += _perVertexSize) {
_tempPos.x = clippedVertices[v];
_tempPos.y = clippedVertices[v + 1];
_finalColor.set(clippedVertices[v + 2], clippedVertices[v + 3], clippedVertices[v + 4], clippedVertices[v + 5]);
_tempUv.x = clippedVertices[v + 6];
_tempUv.y = clippedVertices[v + 7];
if (_useTint) {
_darkColor.set(clippedVertices[v + 8], clippedVertices[v + 9], clippedVertices[v + 10], clippedVertices[v + 11]);
} else {
_darkColor.set(0, 0, 0, 0);
}
_vertexEffect.transform(_tempPos, _tempUv, _finalColor, _darkColor);
vbuf[offset] = _tempPos.x; // x
vbuf[offset + 1] = _tempPos.y; // y
vbuf[offset + 2] = _tempUv.x; // u
vbuf[offset + 3] = _tempUv.y; // v
uintVData[offset + 4] = _spineColorToInt32(_finalColor);
if (_useTint) {
uintVData[offset + 5] = _spineColorToInt32(_darkColor);
}
}
} else {
for (let v = 0, n = clippedVertices.length, offset = _vertexFloatOffset; v < n; v += _perClipVertexSize, offset += _perVertexSize) {
vbuf[offset] = clippedVertices[v]; // x
vbuf[offset + 1] = clippedVertices[v + 1]; // y
vbuf[offset + 2] = clippedVertices[v + 6]; // u
vbuf[offset + 3] = clippedVertices[v + 7]; // v
_finalColor32 = ((clippedVertices[v + 5]<<24) >>> 0) + (clippedVertices[v + 4]<<16) + (clippedVertices[v + 3]<<8) + clippedVertices[v + 2];
uintVData[offset + 4] = _finalColor32;
if (_useTint) {
_darkColor32 = ((clippedVertices[v + 11]<<24) >>> 0) + (clippedVertices[v + 10]<<16) + (clippedVertices[v + 9]<<8) + clippedVertices[v + 8];
uintVData[offset + 5] = _darkColor32;
}
}
}
}
}
realTimeTraverse (worldMat) {
let vbuf;
let ibuf;
let locSkeleton = _comp._skeleton;
let skeletonColor = locSkeleton.color;
let graphics = _comp._debugRenderer;
let clipper = _comp._clipper;
let material = null;
let attachment, attachmentColor, slotColor, uvs, triangles;
let isRegion, isMesh, isClip;
let offsetInfo;
let slot;
let worldMatm;
_slotRangeStart = _comp._startSlotIndex;
_slotRangeEnd = _comp._endSlotIndex;
_inRange = false;
if (_slotRangeStart == -1) _inRange = true;
_debugSlots = _comp.debugSlots;
_debugBones = _comp.debugBones;
_debugMesh = _comp.debugMesh;
if (graphics && (_debugBones || _debugSlots || _debugMesh)) {
graphics.clear();
graphics.lineWidth = 2;
}
// x y u v r1 g1 b1 a1 r2 g2 b2 a2 or x y u v r g b a
_perClipVertexSize = _useTint ? 12 : 8;
_vertexFloatCount = 0;
_vertexFloatOffset = 0;
_vertexOffset = 0;
_indexCount = 0;
_indexOffset = 0;
for (let slotIdx = 0, slotCount = locSkeleton.drawOrder.length; slotIdx < slotCount; slotIdx++) {
slot = locSkeleton.drawOrder[slotIdx];
if(slot == undefined || !slot.bone.active) {
continue;
}
if (_slotRangeStart >= 0 && _slotRangeStart == slot.data.index) {
_inRange = true;
}
if (!_inRange) {
clipper.clipEndWithSlot(slot);
continue;
}
if (_slotRangeEnd >= 0 && _slotRangeEnd == slot.data.index) {
_inRange = false;
}
_vertexFloatCount = 0;
_indexCount = 0;
attachment = slot.getAttachment();
if (!attachment) {
clipper.clipEndWithSlot(slot);
continue;
}
isRegion = attachment instanceof spine.RegionAttachment;
isMesh = attachment instanceof spine.MeshAttachment;
isClip = attachment instanceof spine.ClippingAttachment;
if (isClip) {
clipper.clipStart(slot, attachment);
continue;
}
if (!isRegion && !isMesh) {
clipper.clipEndWithSlot(slot);
continue;
}
material = _getSlotMaterial(attachment.region.texture._texture, slot.data.blendMode);
if (!material) {
clipper.clipEndWithSlot(slot);
continue;
}
if (_mustFlush || material.getHash() !== _renderer.material.getHash()) {
_mustFlush = false;
_renderer._flush();
_renderer.node = _node;
_renderer.material = material;
}
if (isRegion) {
triangles = _quadTriangles;
// insure capacity
_vertexFloatCount = 4 * _perVertexSize;
_indexCount = 6;
offsetInfo = _buffer.request(4, 6);
_indexOffset = offsetInfo.indiceOffset,
_vertexOffset = offsetInfo.vertexOffset,
_vertexFloatOffset = offsetInfo.byteOffset >> 2;
vbuf = _buffer._vData,
ibuf = _buffer._iData;
// compute vertex and fill x y
attachment.computeWorldVertices(slot.bone, vbuf, _vertexFloatOffset, _perVertexSize);
// draw debug slots if enabled graphics
if (graphics && _debugSlots) {
graphics.strokeColor = _slotColor;
graphics.moveTo(vbuf[_vertexFloatOffset], vbuf[_vertexFloatOffset + 1]);
for (let ii = _vertexFloatOffset + _perVertexSize, nn = _vertexFloatOffset + _vertexFloatCount; ii < nn; ii += _perVertexSize) {
graphics.lineTo(vbuf[ii], vbuf[ii + 1]);
}
graphics.close();
graphics.stroke();
}
}
else if (isMesh) {
triangles = attachment.triangles;
// insure capacity
_vertexFloatCount = (attachment.worldVerticesLength >> 1) * _perVertexSize;
_indexCount = triangles.length;
offsetInfo = _buffer.request(_vertexFloatCount / _perVertexSize, _indexCount);
_indexOffset = offsetInfo.indiceOffset,
_vertexOffset = offsetInfo.vertexOffset,
_vertexFloatOffset = offsetInfo.byteOffset >> 2;
vbuf = _buffer._vData,
ibuf = _buffer._iData;
// compute vertex and fill x y
attachment.computeWorldVertices(slot, 0, attachment.worldVerticesLength, vbuf, _vertexFloatOffset, _perVertexSize);
// draw debug mesh if enabled graphics
if (graphics && _debugMesh) {
graphics.strokeColor = _meshColor;
for (let ii = 0, nn = triangles.length; ii < nn; ii += 3) {
let v1 = triangles[ii] * _perVertexSize + _vertexFloatOffset;
let v2 = triangles[ii + 1] * _perVertexSize + _vertexFloatOffset;
let v3 = triangles[ii + 2] * _perVertexSize + _vertexFloatOffset;
graphics.moveTo(vbuf[v1], vbuf[v1 + 1]);
graphics.lineTo(vbuf[v2], vbuf[v2 + 1]);
graphics.lineTo(vbuf[v3], vbuf[v3 + 1]);
graphics.close();
graphics.stroke();
}
}
}
if (_vertexFloatCount == 0 || _indexCount == 0) {
clipper.clipEndWithSlot(slot);
continue;
}
// fill indices
ibuf.set(triangles, _indexOffset);
// fill u v
uvs = attachment.uvs;
for (let v = _vertexFloatOffset, n = _vertexFloatOffset + _vertexFloatCount, u = 0; v < n; v += _perVertexSize, u += 2) {
vbuf[v + 2] = uvs[u]; // u
vbuf[v + 3] = uvs[u + 1]; // v
}
attachmentColor = attachment.color,
slotColor = slot.color;
this.fillVertices(skeletonColor, attachmentColor, slotColor, clipper, slot);
// reset buffer pointer, because clipper maybe realloc a new buffer in file Vertices function.
vbuf = _buffer._vData,
ibuf = _buffer._iData;
if (_indexCount > 0) {
for (let ii = _indexOffset, nn = _indexOffset + _indexCount; ii < nn; ii++) {
ibuf[ii] += _vertexOffset;
}
if (worldMat) {
worldMatm = worldMat.m;
_m00 = worldMatm[0];
_m04 = worldMatm[4];
_m12 = worldMatm[12];
_m01 = worldMatm[1];
_m05 = worldMatm[5];
_m13 = worldMatm[13];
for (let ii = _vertexFloatOffset, nn = _vertexFloatOffset + _vertexFloatCount; ii < nn; ii += _perVertexSize) {
_x = vbuf[ii];
_y = vbuf[ii + 1];
vbuf[ii] = _x * _m00 + _y * _m04 + _m12;
vbuf[ii + 1] = _x * _m01 + _y * _m05 + _m13;
}
}
_buffer.adjust(_vertexFloatCount / _perVertexSize, _indexCount);
}
clipper.clipEndWithSlot(slot);
}
clipper.clipEnd();
if (graphics && _debugBones) {
let bone;
graphics.strokeColor = _boneColor;
graphics.fillColor = _slotColor; // Root bone color is same as slot color.
for (let i = 0, n = locSkeleton.bones.length; i < n; i++) {
bone = locSkeleton.bones[i];
let x = bone.data.length * bone.a + bone.worldX;
let y = bone.data.length * bone.c + bone.worldY;
// Bone lengths.
graphics.moveTo(bone.worldX, bone.worldY);
graphics.lineTo(x, y);
graphics.stroke();
// Bone origins.
graphics.circle(bone.worldX, bone.worldY, Math.PI * 1.5);
graphics.fill();
if (i === 0) {
graphics.fillColor = _originColor;
}
}
}
}
cacheTraverse (worldMat) {
let frame = _comp._curFrame;
if (!frame) return;
let segments = frame.segments;
if (segments.length == 0) return;
let vbuf, ibuf, uintbuf;
let material;
let offsetInfo;
let vertices = frame.vertices;
let indices = frame.indices;
let worldMatm;
let frameVFOffset = 0, frameIndexOffset = 0, segVFCount = 0;
if (worldMat) {
worldMatm = worldMat.m;
_m00 = worldMatm[0];
_m01 = worldMatm[1];
_m04 = worldMatm[4];
_m05 = worldMatm[5];
_m12 = worldMatm[12];
_m13 = worldMatm[13];
}
let justTranslate = _m00 === 1 && _m01 === 0 && _m04 === 0 && _m05 === 1;
let needBatch = (_handleVal & FLAG_BATCH);
let calcTranslate = needBatch && justTranslate;
let colorOffset = 0;
let colors = frame.colors;
let nowColor = colors[colorOffset++];
let maxVFOffset = nowColor.vfOffset;
_handleColor(nowColor);
for (let i = 0, n = segments.length; i < n; i++) {
let segInfo = segments[i];
material = _getSlotMaterial(segInfo.tex, segInfo.blendMode);
if (!material) continue;
if (_mustFlush || material.getHash() !== _renderer.material.getHash()) {
_mustFlush = false;
_renderer._flush();
_renderer.node = _node;
_renderer.material = material;
}
_vertexCount = segInfo.vertexCount;
_indexCount = segInfo.indexCount;
offsetInfo = _buffer.request(_vertexCount, _indexCount);
_indexOffset = offsetInfo.indiceOffset;
_vertexOffset = offsetInfo.vertexOffset;
_vfOffset = offsetInfo.byteOffset >> 2;
vbuf = _buffer._vData;
ibuf = _buffer._iData;
uintbuf = _buffer._uintVData;
for (let ii = _indexOffset, il = _indexOffset + _indexCount; ii < il; ii++) {
ibuf[ii] = _vertexOffset + indices[frameIndexOffset++];
}
segVFCount = segInfo.vfCount;
vbuf.set(vertices.subarray(frameVFOffset, frameVFOffset + segVFCount), _vfOffset);
frameVFOffset += segVFCount;
if (calcTranslate) {
for (let ii = _vfOffset, il = _vfOffset + segVFCount; ii < il; ii += 6) {
vbuf[ii] += _m12;
vbuf[ii + 1] += _m13;
}
} else if (needBatch) {
for (let ii = _vfOffset, il = _vfOffset + segVFCount; ii < il; ii += 6) {
_x = vbuf[ii];
_y = vbuf[ii + 1];
vbuf[ii] = _x * _m00 + _y * _m04 + _m12;
vbuf[ii + 1] = _x * _m01 + _y * _m05 + _m13;
}
}
_buffer.adjust(_vertexCount, _indexCount);
if ( !_needColor ) continue;
// handle color
let frameColorOffset = frameVFOffset - segVFCount;
for (let ii = _vfOffset + 4, il = _vfOffset + 4 + segVFCount; ii < il; ii += 6, frameColorOffset += 6) {
if (frameColorOffset >= maxVFOffset) {
nowColor = colors[colorOffset++];
_handleColor(nowColor);
maxVFOffset = nowColor.vfOffset;
}
uintbuf[ii] = _finalColor32;
uintbuf[ii + 1] = _darkColor32;
}
}
}
fillBuffers (comp, renderer) {
let node = comp.node;
node._renderFlag |= RenderFlow.FLAG_UPDATE_RENDER_DATA;
if (!comp._skeleton) return;
let nodeColor = node._color;
_nodeR = nodeColor.r / 255;
_nodeG = nodeColor.g / 255;
_nodeB = nodeColor.b / 255;
_nodeA = nodeColor.a / 255;
_useTint = comp.useTint || comp.isAnimationCached();
_vertexFormat = _useTint? VFTwoColor : VFOneColor;
// x y u v color1 color2 or x y u v color
_perVertexSize = _useTint ? 6 : 5;
_node = comp.node;
_buffer = renderer.getBuffer('spine', _vertexFormat);
_renderer = renderer;
_comp = comp;
_mustFlush = true;
_premultipliedAlpha = comp.premultipliedAlpha;
_multiplier = 1.0;
_handleVal = 0x00;
_needColor = false;
_vertexEffect = comp._effectDelegate && comp._effectDelegate._vertexEffect;
if (nodeColor._val !== 0xffffffff || _premultipliedAlpha) {
_needColor = true;
}
if (_useTint) {
_handleVal |= FLAG_TWO_COLOR;
}
let worldMat = undefined;
if (_comp.enableBatch) {
worldMat = _node._worldMatrix;
_mustFlush = false;
_handleVal |= FLAG_BATCH;
}
if (comp.isAnimationCached()) {
// Traverse input assembler.
this.cacheTraverse(worldMat);
} else {
if (_vertexEffect) _vertexEffect.begin(comp._skeleton);
this.realTimeTraverse(worldMat);
if (_vertexEffect) _vertexEffect.end();
}
// sync attached node matrix
renderer.worldMatDirty++;
comp.attachUtil._syncAttachedNode();
// Clear temp var.
_node = undefined;
_buffer = undefined;
_renderer = undefined;
_comp = undefined;
_vertexEffect = null;
}
postFillBuffers (comp, renderer) {
renderer.worldMatDirty--;
}
}
Assembler.register(Skeleton, SpineAssembler);

View File

@@ -0,0 +1,42 @@
/****************************************************************************
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.
****************************************************************************/
let TrackEntryListeners = function () {
this.start = null;
this.end = null;
this.complete = null;
this.event = null;
this.interrupt = null;
this.dispose = null;
};
TrackEntryListeners.getListeners = function(entry){
if (!entry.listener) {
entry.listener = new TrackEntryListeners();
}
return entry.listener;
};
module.exports = TrackEntryListeners;

View File

@@ -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.
****************************************************************************/
const spine = require('./lib/spine');
/**
* @module sp
*/
/**
* !#en
* The delegate of spine vertex effect
* !#zh
* Spine 顶点动画代理
* @class VertexEffectDelegate
*/
sp.VertexEffectDelegate = cc.Class({
name: 'sp.VertexEffectDelegate',
ctor () {
this._vertexEffect = null;
this._interpolation = null;
this._effectType = 'none';
},
/**
* !#en Clears vertex effect.
* !#zh 清空顶点效果
* @method clear
*/
clear () {
this._vertexEffect = null;
this._interpolation = null;
this._effectType = 'none';
},
/**
* !#en Inits delegate with jitter effect
* !#zh 设置顶点抖动效果
* @method initJitter
* @param {Number} jitterX
* @param {Number} jitterY
*/
initJitter (jitterX, jitterY) {
this._effectType = 'jitter';
this._vertexEffect = new spine.JitterEffect(jitterX, jitterY);
return this._vertexEffect;
},
/**
* !#en Inits delegate with swirl effect
* !#zh 设置顶点漩涡效果
* @method initSwirlWithPow
* @param {Number} radius
* @param {Number} power
* @return {sp.spine.JitterEffect}
*/
initSwirlWithPow(radius, power) {
this._interpolation = new spine.Pow(power);
this._vertexEffect = new spine.SwirlEffect(radius, this._interpolation);
return this._vertexEffect;
},
/**
* !#en Inits delegate with swirl effect
* !#zh 设置顶点漩涡效果
* @method initSwirlWithPowOut
* @param {Number} radius
* @param {Number} power
* @return {sp.spine.SwirlEffect}
*/
initSwirlWithPowOut(radius, power) {
this._interpolation = new spine.PowOut(power);
this._vertexEffect = new spine.SwirlEffect(radius, this._interpolation);
return this._vertexEffect;
},
/**
* !#en Gets jitter vertex effect
* !#zh 获取顶点抖动效果
* @method getJitterVertexEffect
* @return {sp.spine.JitterEffect}
*/
getJitterVertexEffect () {
return this._vertexEffect;
},
/**
* !#en Gets swirl vertex effect
* !#zh 获取顶点漩涡效果
* @method getSwirlVertexEffect
* @return {sp.spine.SwirlEffect}
*/
getSwirlVertexEffect () {
return this._vertexEffect;
},
/**
* !#en Gets vertex effect
* !#zh 获取顶点效果
* @method getVertexEffect
* @return {sp.spine.JitterEffect|sp.spine.SwirlEffect}
*/
getVertexEffect () {
return this._vertexEffect;
},
/**
* !#en Gets effect type
* !#zh 获取效果类型
* @method getEffectType
* @return {String}
*/
getEffectType () {
return this._effectType;
}
});
module.exports = sp.VertexEffectDelegate;