初始化

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,167 @@
/****************************************************************************
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
* cc.NodePool is the cache pool designed for node type.<br/>
* It can helps you to improve your game performance for objects which need frequent release and recreate operations<br/>
*
* It's recommended to create cc.NodePool instances by node type, the type corresponds to node type in game design, not the class,
* for example, a prefab is a specific node type. <br/>
* When you create a node pool, you can pass a Component which contains `unuse`, `reuse` functions to control the content of node.<br/>
*
* Some common use case is :<br/>
* 1. Bullets in game (die very soon, massive creation and recreation, no side effect on other objects)<br/>
* 2. Blocks in candy crash (massive creation and recreation)<br/>
* etc...
* !#zh
* cc.NodePool 是用于管理节点对象的对象缓存池。<br/>
* 它可以帮助您提高游戏性能,适用于优化对象的反复创建和销毁<br/>
* 以前 cocos2d-x 中的 cc.pool 和新的节点事件注册系统不兼容,因此请使用 cc.NodePool 来代替。
*
* 新的 NodePool 需要实例化之后才能使用,每种不同的节点对象池需要一个不同的对象池实例,这里的种类对应于游戏中的节点设计,一个 prefab 相当于一个种类的节点。<br/>
* 在创建缓冲池时,可以传入一个包含 unuse, reuse 函数的组件类型用于节点的回收和复用逻辑。<br/>
*
* 一些常见的用例是:<br/>
* 1.在游戏中的子弹(死亡很快,频繁创建,对其他对象无副作用)<br/>
* 2.糖果粉碎传奇中的木块(频繁创建)。
* 等等....
* @class NodePool
*/
/**
* !#en
* Constructor for creating a pool for a specific node template (usually a prefab). You can pass a component (type or name) argument for handling event for reusing and recycling node.
* !#zh
* 使用构造函数来创建一个节点专用的对象池,您可以传递一个组件类型或名称,用于处理节点回收和复用时的事件逻辑。
* @method constructor
* @param {Function|String} [poolHandlerComp] !#en The constructor or the class name of the component to control the unuse/reuse logic. !#zh 处理节点回收和复用事件逻辑的组件类型或名称。
* @example
* properties: {
* template: cc.Prefab
* },
* onLoad () {
// MyTemplateHandler is a component with 'unuse' and 'reuse' to handle events when node is reused or recycled.
* this.myPool = new cc.NodePool('MyTemplateHandler');
* }
* @typescript
* constructor(poolHandlerComp?: {prototype: Component}|string)
*/
cc.NodePool = function (poolHandlerComp) {
/**
* !#en The pool handler component, it could be the class name or the constructor.
* !#zh 缓冲池处理组件,用于节点的回收和复用逻辑,这个属性可以是组件类名或组件的构造函数。
* @property poolHandlerComp
* @type {Function|String}
*/
this.poolHandlerComp = poolHandlerComp;
this._pool = [];
};
cc.NodePool.prototype = {
constructor: cc.NodePool,
/**
* !#en The current available size in the pool
* !#zh 获取当前缓冲池的可用对象数量
* @method size
* @return {Number}
*/
size: function () {
return this._pool.length;
},
/**
* !#en Destroy all cached nodes in the pool
* !#zh 销毁对象池中缓存的所有节点
* @method clear
*/
clear: function () {
var count = this._pool.length;
for (var i = 0; i < count; ++i) {
this._pool[i].destroy();
}
this._pool.length = 0;
},
/**
* !#en Put a new Node into the pool.
* It will automatically remove the node from its parent without cleanup.
* It will also invoke unuse method of the poolHandlerComp if exist.
* !#zh 向缓冲池中存入一个不再需要的节点对象。
* 这个函数会自动将目标节点从父节点上移除,但是不会进行 cleanup 操作。
* 这个函数会调用 poolHandlerComp 的 unuse 函数,如果组件和函数都存在的话。
* @method put
* @param {Node} obj
* @example
* let myNode = cc.instantiate(this.template);
* this.myPool.put(myNode);
*/
put: function (obj) {
if (obj && this._pool.indexOf(obj) === -1) {
// Remove from parent, but don't cleanup
obj.removeFromParent(false);
// Invoke pool handler
var handler = this.poolHandlerComp ? obj.getComponent(this.poolHandlerComp) : null;
if (handler && handler.unuse) {
handler.unuse();
}
this._pool.push(obj);
}
},
/**
* !#en Get a obj from pool, if no available object in pool, null will be returned.
* This function will invoke the reuse function of poolHandlerComp if exist.
* !#zh 获取对象池中的对象,如果对象池没有可用对象,则返回空。
* 这个函数会调用 poolHandlerComp 的 reuse 函数,如果组件和函数都存在的话。
* @method get
* @param {any} ...params - !#en Params to pass to 'reuse' method in poolHandlerComp !#zh 向 poolHandlerComp 中的 'reuse' 函数传递的参数
* @return {Node|null}
* @example
* let newNode = this.myPool.get();
*/
get: function () {
var last = this._pool.length-1;
if (last < 0) {
return null;
}
else {
// Pop the last object in pool
var obj = this._pool[last];
this._pool.length = last;
// Invoke pool handler
var handler = this.poolHandlerComp ? obj.getComponent(this.poolHandlerComp) : null;
if (handler && handler.reuse) {
handler.reuse.apply(handler, arguments);
}
return obj;
}
}
};
module.exports = cc.NodePool;

View File

@@ -0,0 +1,521 @@
/****************************************************************************
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 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 _preColor = null;
let _x, _y;
//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.isCompleted = false;
this._frameIdx = -1;
this._armatureInfo = null;
this._animationName = null;
this._tempSegments = null;
this._tempColors = null;
this._tempBoneInfos = null;
},
init (armatureInfo, animationName) {
this._inited = true;
this._armatureInfo = armatureInfo;
this._animationName = animationName;
},
// 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();
},
begin () {
if (!this._invalid) return;
let armatureInfo = this._armatureInfo;
let curAnimationCache = armatureInfo.curAnimationCache;
if (curAnimationCache && curAnimationCache != this) {
if (this._privateMode) {
curAnimationCache.invalidAllFrame();
} else {
curAnimationCache.updateToFrame();
}
}
let armature = armatureInfo.armature;
let animation = armature.animation;
animation.play(this._animationName, 1);
armatureInfo.curAnimationCache = this;
this._invalid = false;
this._frameIdx = -1;
this.totalTime = 0;
this.isCompleted = false;
},
end () {
if (!this._needToUpdate()) {
this._armatureInfo.curAnimationCache = null;
this.frames.length = this._frameIdx + 1;
this.isCompleted = true;
}
},
_needToUpdate (toFrameIdx) {
let armatureInfo = this._armatureInfo;
let armature = armatureInfo.armature;
let animation = armature.animation;
return !animation.isCompleted &&
this.totalTime < MaxCacheTime &&
(toFrameIdx == undefined || this._frameIdx < toFrameIdx);
},
updateToFrame (toFrameIdx) {
if (!this._inited) return;
this.begin();
if (!this._needToUpdate(toFrameIdx)) return;
let armatureInfo = this._armatureInfo;
let armature = armatureInfo.armature;
do {
// Solid update frame rate 1/60.
armature.advanceTime(FrameTime);
this._frameIdx++;
this._updateFrame(armature, 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 (armature, index) {
_vfOffset = 0;
_boneInfoOffset = 0;
_indexOffset = 0;
_vertexOffset = 0;
_preTexUrl = null;
_preBlendMode = null;
_segVCount = 0;
_segICount = 0;
_segOffset = 0;
_colorOffset = 0;
_preColor = 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._traverseArmature(armature, 1.0);
// At last must handle pre color and segment.
// Because vertex count will right at the end.
// Handle pre color.
if (_colorOffset > 0) {
colors[_colorOffset - 1].vfOffset = _vfOffset;
}
colors.length = _colorOffset;
boneInfos.length = _boneInfoOffset;
// Handle pre segment
let preSegOffset = _segOffset - 1;
if (preSegOffset >= 0) {
if (_segICount > 0) {
let preSegInfo = segments[preSegOffset];
preSegInfo.indexCount = _segICount;
preSegInfo.vfCount = _segVCount * 5;
preSegInfo.vertexCount = _segVCount;
segments.length = _segOffset;
} else {
segments.length = _segOffset - 1;
}
}
// 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++]; // color
}
// 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;
},
_traverseArmature (armature, parentOpacity) {
let colors = this._tempColors;
let segments = this._tempSegments;
let boneInfos = this._tempBoneInfos;
let gVertices = _vertices;
let gIndices = _indices;
let slotVertices, slotIndices;
let slots = armature._slots, slot, slotMatrix, slotMatrixm, slotColor, colorVal;
let texture;
let preSegOffset, preSegInfo;
let bones = armature._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] = {
globalTransformMatrix: new dragonBones.Matrix(),
};
}
let boneMat = bone.globalTransformMatrix;
let cacheBoneMat = boneInfo.globalTransformMatrix;
cacheBoneMat.copyFrom(boneMat);
}
}
for (let i = 0, l = slots.length; i < l; i++) {
slot = slots[i];
if (!slot._visible || !slot._displayData) continue;
slot.updateWorldMatrix();
slotColor = slot._color;
if (slot.childArmature) {
this._traverseArmature(slot.childArmature, parentOpacity * slotColor.a / 255);
continue;
}
texture = slot.getTexture();
if (!texture) continue;
if (_preTexUrl !== texture.nativeUrl || _preBlendMode !== slot._blendMode) {
_preTexUrl = texture.nativeUrl;
_preBlendMode = slot._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 * 5;
} else {
// Discard pre segment.
_segOffset--;
}
}
// Handle now segment.
segments[_segOffset] = {
tex : texture,
blendMode : slot._blendMode,
indexCount : 0,
vertexCount : 0,
vfCount : 0
};
_segOffset++;
_segICount = 0;
_segVCount = 0;
}
colorVal = ((slotColor.a * parentOpacity << 24) >>> 0) + (slotColor.b << 16) + (slotColor.g << 8) + slotColor.r;
if (_preColor !== colorVal) {
_preColor = colorVal;
if (_colorOffset > 0) {
colors[_colorOffset - 1].vfOffset = _vfOffset;
}
colors[_colorOffset++] = {
r : slotColor.r,
g : slotColor.g,
b : slotColor.b,
a : slotColor.a * parentOpacity,
vfOffset : 0
}
}
slotVertices = slot._localVertices;
slotIndices = slot._indices;
slotMatrix = slot._worldMatrix;
slotMatrixm = slotMatrix.m;
for (let j = 0, vl = slotVertices.length; j < vl;) {
_x = slotVertices[j++];
_y = slotVertices[j++];
gVertices[_vfOffset++] = _x * slotMatrixm[0] + _y * slotMatrixm[4] + slotMatrixm[12];
gVertices[_vfOffset++] = _x * slotMatrixm[1] + _y * slotMatrixm[5] + slotMatrixm[13];
gVertices[_vfOffset++] = slotVertices[j++];
gVertices[_vfOffset++] = slotVertices[j++];
gVertices[_vfOffset++] = colorVal;
}
// This place must use segment vertex count to calculate vertex offset.
// Assembler will calculate vertex offset again for different segment.
for (let ii = 0, il = slotIndices.length; ii < il; ii ++) {
gIndices[_indexOffset++] = _segVCount + slotIndices[ii];
}
_vertexOffset = _vfOffset / 5;
_segICount += slotIndices.length;
_segVCount += slotVertices.length / 4;
}
},
});
let ArmatureCache = cc.Class({
ctor () {
this._privateMode = false;
this._animationPool = {};
this._armatureCache = {};
},
enablePrivateMode () {
this._privateMode = true;
},
// If cache is private, cache will be destroy when dragonbones node destroy.
dispose () {
for (var key in this._armatureCache) {
var armatureInfo = this._armatureCache[key];
if (armatureInfo) {
let armature = armatureInfo.armature;
armature && armature.dispose();
}
}
this._armatureCache = null;
this._animationPool = null;
},
_removeArmature (armatureKey) {
var armatureInfo = this._armatureCache[armatureKey];
let animationsCache = armatureInfo.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[armatureKey + "#" + aniKey] = animationCache;
animationCache.clear();
}
let armature = armatureInfo.armature;
armature && armature.dispose();
delete this._armatureCache[armatureKey];
},
// When db assets be destroy, remove armature from db cache.
resetArmature (uuid) {
for (var armatureKey in this._armatureCache) {
if (armatureKey.indexOf(uuid) == -1) continue;
this._removeArmature(armatureKey);
}
},
getArmatureCache (armatureName, armatureKey, atlasUUID) {
let armatureInfo = this._armatureCache[armatureKey];
let armature;
if (!armatureInfo) {
let factory = dragonBones.CCFactory.getInstance();
let proxy = factory.buildArmatureDisplay(armatureName, armatureKey, "", atlasUUID);
if (!proxy || !proxy._armature) return;
armature = proxy._armature;
// If armature has child armature, can not be cache, because it's
// animation data can not be precompute.
if (!ArmatureCache.canCache(armature)) {
armature.dispose();
return;
}
this._armatureCache[armatureKey] = {
armature : armature,
// Cache all kinds of animation frame.
// When armature is dispose, clear all animation cache.
animationsCache : {},
curAnimationCache: null,
};
} else {
armature = armatureInfo.armature;
}
return armature;
},
getAnimationCache (armatureKey, animationName) {
let armatureInfo = this._armatureCache[armatureKey];
if (!armatureInfo) return null;
let animationsCache = armatureInfo.animationsCache;
return animationsCache[animationName];
},
initAnimationCache (armatureKey, animationName) {
if (!animationName) return null;
let armatureInfo = this._armatureCache[armatureKey];
let armature = armatureInfo && armatureInfo.armature;
if (!armature) return null;
let animation = armature.animation;
let hasAni = animation.hasAnimation(animationName);
if (!hasAni) return null;
let animationsCache = armatureInfo.animationsCache;
let animationCache = animationsCache[animationName];
if (!animationCache) {
// If cache exist in pool, then just use it.
let poolKey = armatureKey + "#" + animationName;
animationCache = this._animationPool[poolKey];
if (animationCache) {
delete this._animationPool[poolKey];
} else {
animationCache = new AnimationCache();
animationCache._privateMode = this._privateMode;
}
animationCache.init(armatureInfo, animationName);
animationsCache[animationName] = animationCache;
}
return animationCache;
},
invalidAnimationCache (armatureKey) {
let armatureInfo = this._armatureCache[armatureKey];
let armature = armatureInfo && armatureInfo.armature;
if (!armature) return null;
let animationsCache = armatureInfo.animationsCache;
for (var aniKey in animationsCache) {
let animationCache = animationsCache[aniKey];
animationCache.invalidAllFrame();
}
},
updateAnimationCache (armatureKey, animationName) {
if (animationName) {
let animationCache = this.initAnimationCache(armatureKey, animationName);
if (!animationCache) return;
animationCache.updateAllFrame();
} else {
let armatureInfo = this._armatureCache[armatureKey];
let armature = armatureInfo && armatureInfo.armature;
if (!armature) return null;
let animationsCache = armatureInfo.animationsCache;
for (var aniKey in animationsCache) {
let animationCache = animationsCache[aniKey];
animationCache.updateAllFrame();
}
}
},
});
ArmatureCache.FrameTime = FrameTime;
ArmatureCache.sharedCache = new ArmatureCache();
ArmatureCache.canCache = function (armature) {
let slots = armature._slots;
for (let i = 0, l = slots.length; i < l; i++) {
let slot = slots[i];
if (slot.childArmature) {
return false;
}
}
return true;
},
module.exports = ArmatureCache;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,506 @@
/****************************************************************************
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 dragonBones
*/
/**
* !#en Attach node tool
* !#zh 挂点工具类
* @class dragonBones.AttachUtil
*/
let AttachUtil = cc.Class({
name: 'dragonBones.AttachUtil',
ctor () {
this._inited = false;
this._armature = null;
this._armatureNode = null;
this._armatureDisplay = null;
this._attachedRootNode = null;
this._attachedNodeArray = [];
this._boneIndexToNode = {};
},
init (armatureDisplay) {
this._inited = true;
this._armature = armatureDisplay._armature;
this._armatureNode = armatureDisplay.node;
this._armatureDisplay = armatureDisplay;
},
reset () {
this._inited = false;
this._armature = null;
this._armatureNode = null;
this._armatureDisplay = null;
},
_prepareAttachNode () {
let armature = this._armature;
if (!armature) {
return;
}
let rootNode = this._armatureNode.getChildByName(ATTACHED_ROOT_NAME);
if (!rootNode || !rootNode.isValid) {
rootNode = new cc.Node(ATTACHED_ROOT_NAME);
limitNode(rootNode);
this._armatureNode.addChild(rootNode);
}
let isCached = this._armatureDisplay.isAnimationCached();
if (isCached && this._armatureDisplay._frameCache) {
this._armatureDisplay._frameCache.enableCacheAttachedInfo();
}
this._attachedRootNode = rootNode;
return rootNode;
},
_buildBoneAttachedNode (bone, boneIndex) {
let boneNodeName = ATTACHED_PRE_NAME + bone.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 boneIndex = 0;
let res = [];
let attachedTraverse = function (armature) {
if (!armature) return;
let bones = armature.getBones(), bone;
for(let i = 0, l = bones.length; i < l; i++) {
bone = bones[i];
bone._boneIndex = boneIndex++;
if (boneName === bone.name) {
res.push(bone);
}
}
let slots = armature.getSlots(), slot;
for (let i = 0, l = slots.length; i < l; i++) {
slot = slots[i];
if (slot.childArmature) {
attachedTraverse(slot.childArmature);
}
}
}.bind(this);
attachedTraverse(this._armature);
let buildBoneTree = function (bone) {
if (!bone) return;
let boneNode = this._getNodeByBoneIndex(bone._boneIndex);
if (boneNode) return boneNode;
boneNode = this._buildBoneAttachedNode(bone, bone._boneIndex);
let subArmatureParentBone = null;
if (bone.armature.parent) {
let parentSlot = bone.armature.parent;
subArmatureParentBone = parentSlot.parent;
}
let parentBoneNode = buildBoneTree(bone.parent || subArmatureParentBone) || rootNode;
boneNode.parent = parentBoneNode;
if (bone.parent) {
boneNode._rootNode = parentBoneNode._rootNode;
} else {
boneNode._rootNode = parentBoneNode;
}
return boneNode;
}.bind(this);
for (let i = 0, n = res.length; i < n; i++) {
let targetNode = buildBoneTree(res[i]);
if (targetNode) {
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._armatureNode.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 boneIndex = 0;
let attachedTraverse = function (armature) {
if (!armature) return;
let subArmatureParentNode = rootNode;
if (armature.parent) {
let parentSlot = armature.parent;
let parentBone = parentSlot.parent;
subArmatureParentNode = parentBone._attachedNode;
}
let bones = armature.getBones(), bone;
for(let i = 0, l = bones.length; i < l; i++) {
let curBoneIndex = boneIndex++;
bone = bones[i];
bone._attachedNode = null;
let parentNode = null;
if (bone.parent) {
parentNode = bone.parent._attachedNode;
} else {
parentNode = subArmatureParentNode;
}
if (parentNode) {
let boneNode = parentNode.getChildByName(ATTACHED_PRE_NAME + bone.name);
if (!boneNode || !boneNode.isValid) {
boneNode = this._buildBoneAttachedNode(bone, curBoneIndex);
parentNode.addChild(boneNode);
} else {
this._buildBoneRelation(boneNode, bone, curBoneIndex);
}
boneNode._rootNode = subArmatureParentNode;
bone._attachedNode = boneNode;
}
}
let slots = armature.getSlots(), slot;
for (let i = 0, l = slots.length; i < l; i++) {
slot = slots[i];
if (slot.childArmature) {
attachedTraverse(slot.childArmature);
}
}
}.bind(this);
attachedTraverse(this._armature);
return rootNode;
},
_hasAttachedNode () {
if (!this._inited) return false;
let attachedRootNode = this._armatureNode.getChildByName(ATTACHED_ROOT_NAME);
return !!attachedRootNode;
},
_associateAttachedNode () {
if (!this._inited) return;
let rootNode = this._armatureNode.getChildByName(ATTACHED_ROOT_NAME);
if (!rootNode || !rootNode.isValid) return;
this._attachedRootNode = rootNode;
// clear all records
this._boneIndexToNode = {};
let nodeArray = this._attachedNodeArray;
nodeArray.length = 0;
let armature = this._armature;
if (!armature) {
return;
}
limitNode(rootNode);
if (!CC_NATIVERENDERER) {
let isCached = this._armatureDisplay.isAnimationCached();
if (isCached && this._armatureDisplay._frameCache) {
this._armatureDisplay._frameCache.enableCacheAttachedInfo();
}
}
let boneIndex = 0;
let attachedTraverse = function (armature) {
if (!armature) return;
let subArmatureParentNode = rootNode;
if (armature.parent) {
let parentSlot = armature.parent;
let parentBone = parentSlot.parent;
subArmatureParentNode = parentBone._attachedNode;
}
let bones = armature.getBones(), bone;
for(let i = 0, l = bones.length; i < l; i++) {
let curBoneIndex = boneIndex++;
bone = bones[i];
bone._attachedNode = null;
let parentNode = null;
if (bone.parent) {
parentNode = bone.parent._attachedNode;
} else {
parentNode = subArmatureParentNode;
}
if (parentNode) {
let boneNode = parentNode.getChildByName(ATTACHED_PRE_NAME + bone.name);
if (boneNode && boneNode.isValid) {
this._buildBoneRelation(boneNode, bone, curBoneIndex);
boneNode._rootNode = subArmatureParentNode;
bone._attachedNode = boneNode;
}
}
}
let slots = armature.getSlots(), slot;
for (let i = 0, l = slots.length; i < l; i++) {
slot = slots[i];
if (slot.childArmature) {
attachedTraverse(slot.childArmature);
}
}
}.bind(this);
attachedTraverse(armature);
},
_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._armatureNode._worldMatrix;
Mat4.copy(rootNode._worldMatrix, rootMatrix);
rootNode._renderFlag &= ~FLAG_TRANSFORM;
let boneInfos = null;
let isCached = this._armatureDisplay.isAnimationCached();
if (isCached) {
boneInfos = this._armatureDisplay._curFrame && this._armatureDisplay._curFrame.boneInfos;
if (!boneInfos) return;
}
let mulMat = this._armatureNode._mulMat;
let matrixHandle = function (nodeMat, parentMat, boneMat) {
let tm = _tempMat4.m;
tm[0] = boneMat.a;
tm[1] = boneMat.b;
tm[4] = -boneMat.c;
tm[5] = -boneMat.d;
tm[12] = boneMat.tx;
tm[13] = boneMat.ty;
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 = isCached ? boneInfos[boneNode._boneIndex] : boneNode._bone;
// Bone has been destroy
if (!bone || bone._isInPool) {
boneNode.removeFromParent(true);
boneNode.destroy();
nodeArray[i] = null;
nodeArrayDirty = true;
continue;
}
matrixHandle(boneNode._worldMatrix, boneNode._rootNode._worldMatrix, bone.globalTransformMatrix);
boneNode._renderFlag &= ~FLAG_TRANSFORM;
}
if (nodeArrayDirty) {
this._rebuildNodeArray();
}
},
});
module.exports = dragonBones.AttachUtil = AttachUtil;

View File

@@ -0,0 +1,125 @@
/****************************************************************************
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.
****************************************************************************/
let EventTarget = require('../../cocos2d/core/event/event-target');
dragonBones.CCArmatureDisplay = cc.Class({
name: 'dragonBones.CCArmatureDisplay',
properties: {
// adapt old api
node: {
get () {
return this;
}
},
},
ctor () {
this._eventTarget = new EventTarget();
},
setEventTarget (eventTarget) {
this._eventTarget = eventTarget;
},
getRootDisplay () {
var parentSlot = this._armature._parent;
if (!parentSlot) {
return this;
}
var slot;
while (parentSlot)
{
slot = parentSlot;
parentSlot = parentSlot._armature._parent;
}
return slot._armature.getDisplay();
},
convertToRootSpace (pos) {
var slot = this._armature._parent;
if (!slot)
{
return pos;
}
slot.updateWorldMatrix();
let worldMatrix = slot._worldMatrix;
let worldMatrixm = worldMatrix.m;
let newPos = cc.v2(0,0);
newPos.x = pos.x * worldMatrixm[0] + pos.y * worldMatrixm[4] + worldMatrixm[12];
newPos.y = pos.x * worldMatrixm[1] + pos.y * worldMatrixm[5] + worldMatrixm[13];
return newPos;
},
convertToWorldSpace (point) {
var newPos = this.convertToRootSpace(point);
var ccNode = this.getRootNode();
var finalPos = ccNode.convertToWorldSpaceAR(newPos);
return finalPos;
},
getRootNode () {
var rootDisplay = this.getRootDisplay();
return rootDisplay && rootDisplay._ccNode;
},
////////////////////////////////////
// dragonbones api
dbInit (armature) {
this._armature = armature;
},
dbClear () {
this._armature = null;
},
dbUpdate () {
},
advanceTimeBySelf (on) {
this.shouldAdvanced = !!on;
},
hasDBEventListener (type) {
return this._eventTarget.hasEventListener(type);
},
addDBEventListener (type, listener, target) {
this._eventTarget.on(type, listener, target);
},
removeDBEventListener (type, listener, target) {
this._eventTarget.off(type, listener, target);
},
dispatchDBEvent (type, eventObject) {
this._eventTarget.emit(type, eventObject);
}
////////////////////////////////////
});

View File

@@ -0,0 +1,187 @@
/****************************************************************************
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.
****************************************************************************/
let BaseObject = dragonBones.BaseObject,
BaseFactory = dragonBones.BaseFactory;
/**
* @module dragonBones
*/
/**
* DragonBones factory
* @class CCFactory
* @extends BaseFactory
*/
var CCFactory = dragonBones.CCFactory = cc.Class({
name: 'dragonBones.CCFactory',
extends: BaseFactory,
/**
* @method getInstance
* @return {CCFactory}
* @static
* @example
* let factory = dragonBones.CCFactory.getInstance();
*/
statics: {
_factory: null,
getInstance () {
if (!CCFactory._factory) {
CCFactory._factory = new CCFactory();
}
return CCFactory._factory;
}
},
ctor () {
let eventManager = new dragonBones.CCArmatureDisplay();
this._dragonBones = new dragonBones.DragonBones(eventManager);
if (!CC_NATIVERENDERER && !CC_EDITOR && cc.director._scheduler) {
cc.game.on(cc.game.EVENT_RESTART, this.initUpdate, this);
this.initUpdate();
}
},
initUpdate (dt) {
cc.director._scheduler.enableForTarget(this);
cc.director._scheduler.scheduleUpdate(this, cc.Scheduler.PRIORITY_SYSTEM, false);
},
update (dt) {
this._dragonBones.advanceTime(dt);
},
getDragonBonesDataByRawData (rawData) {
var dataParser = rawData instanceof ArrayBuffer ? BaseFactory._binaryParser : this._dataParser;
return dataParser.parseDragonBonesData(rawData, 1.0);
},
// Build new aramture with a new display.
buildArmatureDisplay (armatureName, dragonBonesName, skinName, textureAtlasName) {
let armature = this.buildArmature(armatureName, dragonBonesName, skinName, textureAtlasName);
return armature && armature._display;
},
// Build sub armature from an exist armature component.
// It will share dragonAsset and dragonAtlasAsset.
// But node can not share,or will cause render error.
createArmatureNode (comp, armatureName, node) {
node = node || new cc.Node();
let display = node.getComponent(dragonBones.ArmatureDisplay);
if (!display) {
display = node.addComponent(dragonBones.ArmatureDisplay);
}
node.name = armatureName;
display._armatureName = armatureName;
display._N$dragonAsset = comp.dragonAsset;
display._N$dragonAtlasAsset = comp.dragonAtlasAsset;
display._init();
return display;
},
_buildTextureAtlasData (textureAtlasData, textureAtlas) {
if (textureAtlasData) {
textureAtlasData.renderTexture = textureAtlas;
}
else {
textureAtlasData = BaseObject.borrowObject(dragonBones.CCTextureAtlasData);
}
return textureAtlasData;
},
_sortSlots () {
let slots = this._slots;
let sortedSlots = [];
for (let i = 0, l = slots.length; i < l; i++) {
let slot = slots[i];
let zOrder = slot._zOrder;
let inserted = false;
for (let j = sortedSlots.length - 1; j >= 0; j--) {
if (zOrder >= sortedSlots[j]._zOrder) {
sortedSlots.splice(j+1, 0, slot);
inserted = true;
break;
}
}
if (!inserted) {
sortedSlots.unshift(slot);
}
}
this._slots = sortedSlots;
},
_buildArmature (dataPackage) {
let armature = BaseObject.borrowObject(dragonBones.Armature);
armature._skinData = dataPackage.skin;
armature._animation = BaseObject.borrowObject(dragonBones.Animation);
armature._animation._armature = armature;
armature._animation.animations = dataPackage.armature.animations;
armature._isChildArmature = false;
// fixed dragonbones sort issue
// armature._sortSlots = this._sortSlots;
var display = new dragonBones.CCArmatureDisplay();
armature.init(dataPackage.armature,
display, display, this._dragonBones
);
return armature;
},
_buildSlot (dataPackage, slotData, displays) {
let slot = BaseObject.borrowObject(dragonBones.CCSlot);
let display = slot;
slot.init(slotData, displays, display, display);
return slot;
},
getDragonBonesDataByUUID (uuid) {
for (var name in this._dragonBonesDataMap) {
if (name.indexOf(uuid) != -1) {
return this._dragonBonesDataMap[name];
}
}
return null;
},
removeDragonBonesDataByUUID (uuid, disposeData) {
if (disposeData === void 0) { disposeData = true; }
for (var name in this._dragonBonesDataMap) {
if (name.indexOf(uuid) === -1) continue;
if (disposeData) {
this._dragonBones.bufferObject(this._dragonBonesDataMap[name]);
}
delete this._dragonBonesDataMap[name];
}
}
});

View File

@@ -0,0 +1,383 @@
/****************************************************************************
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.
****************************************************************************/
import Mat4 from '../../cocos2d/core/value-types/mat4';
const BinaryOffset = dragonBones.BinaryOffset;
const BoneType = dragonBones.BoneType;
dragonBones.CCSlot = cc.Class({
name: 'dragonBones.CCSlot',
extends: dragonBones.Slot,
ctor () {
this._localVertices = [];
this._indices = [];
this._matrix = cc.mat4();
this._worldMatrix = cc.mat4();
this._worldMatrixDirty = true;
this._visible = false;
this._color = cc.color();
},
_onClear () {
this._super();
this._localVertices.length = 0;
this._indices.length = 0;
Mat4.identity(this._matrix);
Mat4.identity(this._worldMatrix);
this._worldMatrixDirty = true;
this._color = cc.color();
this._visible = false;
},
statics : {
toString: function () {
return "[class dragonBones.CCSlot]";
}
},
// just for adapt to dragonbones api,no need to do any thing
_onUpdateDisplay () {
},
// just for adapt to dragonbones api,no need to do any thing
_initDisplay (value) {
},
_addDisplay () {
this._visible = true;
},
// just for adapt to dragonbones api,no need to do any thing
_replaceDisplay (value) {
},
_removeDisplay () {
this._visible = false;
},
// just for adapt to dragonbones api,no need to do any thing
_disposeDisplay (object) {
},
_updateVisible () {
this._visible = this.parent._visible;
},
// just for adapt to dragonbones api,no need to do any thing
_updateZOrder () {
},
_updateBlendMode () {
if (this._childArmature) {
let childSlots = this._childArmature.getSlots();
for (let i = 0, l = childSlots.length; i < l; i++) {
let slot = childSlots[i];
slot._blendMode = this._blendMode;
slot._updateBlendMode();
}
}
},
_updateColor () {
let c = this._color;
c.r = this._colorTransform.redMultiplier * 255;
c.g = this._colorTransform.greenMultiplier * 255;
c.b = this._colorTransform.blueMultiplier * 255;
c.a = this._colorTransform.alphaMultiplier * 255;
},
//return dragonBones.CCTexture2D
getTexture () {
return this._textureData && this._textureData.spriteFrame && this._textureData.spriteFrame.getTexture();
},
_updateFrame () {
this._indices.length = 0;
let indices = this._indices,
localVertices = this._localVertices;
let indexOffset = 0, vfOffset = 0;
let currentTextureData = this._textureData;
if (!this._display || this._displayIndex < 0 || !currentTextureData || !currentTextureData.spriteFrame) return;
let texture = currentTextureData.spriteFrame.getTexture();
let textureAtlasWidth = texture.width;
let textureAtlasHeight = texture.height;
let region = currentTextureData.region;
const currentVerticesData = (this._deformVertices !== null && this._display === this._meshDisplay) ? this._deformVertices.verticesData : null;
if (currentVerticesData) {
const data = currentVerticesData.data;
const intArray = data.intArray;
const floatArray = data.floatArray;
const vertexCount = intArray[currentVerticesData.offset + BinaryOffset.MeshVertexCount];
const triangleCount = intArray[currentVerticesData.offset + BinaryOffset.MeshTriangleCount];
let vertexOffset = intArray[currentVerticesData.offset + BinaryOffset.MeshFloatOffset];
if (vertexOffset < 0) {
vertexOffset += 65536; // Fixed out of bouds bug.
}
const uvOffset = vertexOffset + vertexCount * 2;
const scale = this._armature._armatureData.scale;
for (let i = 0, l = vertexCount * 2; i < l; i += 2) {
localVertices[vfOffset++] = floatArray[vertexOffset + i] * scale;
localVertices[vfOffset++] = -floatArray[vertexOffset + i + 1] * scale;
if (currentVerticesData.rotated) {
localVertices[vfOffset++] = (region.x + (1.0 - floatArray[uvOffset + i]) * region.width) / textureAtlasWidth;
localVertices[vfOffset++] = (region.y + floatArray[uvOffset + i + 1] * region.height) / textureAtlasHeight;
} else {
localVertices[vfOffset++] = (region.x + floatArray[uvOffset + i] * region.width) / textureAtlasWidth;
localVertices[vfOffset++] = (region.y + floatArray[uvOffset + i + 1] * region.height) / textureAtlasHeight;
}
}
for (let i = 0; i < triangleCount * 3; ++i) {
indices[indexOffset++] = intArray[currentVerticesData.offset + BinaryOffset.MeshVertexIndices + i];
}
localVertices.length = vfOffset;
indices.length = indexOffset;
let isSkinned = !!currentVerticesData.weight;
if (isSkinned) {
this._identityTransform();
}
}
else {
let l = region.x / textureAtlasWidth;
let b = (region.y + region.height) / textureAtlasHeight;
let r = (region.x + region.width) / textureAtlasWidth;
let t = region.y / textureAtlasHeight;
localVertices[vfOffset++] = 0; // 0x
localVertices[vfOffset++] = 0; // 0y
localVertices[vfOffset++] = l; // 0u
localVertices[vfOffset++] = b; // 0v
localVertices[vfOffset++] = region.width; // 1x
localVertices[vfOffset++] = 0; // 1y
localVertices[vfOffset++] = r; // 1u
localVertices[vfOffset++] = b; // 1v
localVertices[vfOffset++] = 0; // 2x
localVertices[vfOffset++] = region.height;; // 2y
localVertices[vfOffset++] = l; // 2u
localVertices[vfOffset++] = t; // 2v
localVertices[vfOffset++] = region.width; // 3x
localVertices[vfOffset++] = region.height;; // 3y
localVertices[vfOffset++] = r; // 3u
localVertices[vfOffset++] = t; // 3v
indices[0] = 0;
indices[1] = 1;
indices[2] = 2;
indices[3] = 1;
indices[4] = 3;
indices[5] = 2;
localVertices.length = vfOffset;
indices.length = 6;
}
this._visibleDirty = true;
this._blendModeDirty = true;
this._colorDirty = true;
},
_updateMesh () {
const scale = this._armature._armatureData.scale;
const deformVertices = this._deformVertices.vertices;
const bones = this._deformVertices.bones;
const verticesData = this._deformVertices.verticesData;
const weightData = verticesData.weight;
const hasDeform = deformVertices.length > 0 && verticesData.inheritDeform;
let localVertices = this._localVertices;
if (weightData) {
const data = verticesData.data;
const intArray = data.intArray;
const floatArray = data.floatArray;
const vertexCount = intArray[verticesData.offset + BinaryOffset.MeshVertexCount];
let weightFloatOffset = intArray[weightData.offset + BinaryOffset.WeigthFloatOffset];
if (weightFloatOffset < 0) {
weightFloatOffset += 65536; // Fixed out of bouds bug.
}
for (
let i = 0, iB = weightData.offset + BinaryOffset.WeigthBoneIndices + bones.length, iV = weightFloatOffset, iF = 0, lvi = 0;
i < vertexCount;
i++, lvi+=4
) {
const boneCount = intArray[iB++];
let xG = 0.0, yG = 0.0;
for (let j = 0; j < boneCount; ++j) {
const boneIndex = intArray[iB++];
const bone = bones[boneIndex];
if (bone !== null) {
const matrix = bone.globalTransformMatrix;
const weight = floatArray[iV++];
let xL = floatArray[iV++] * scale;
let yL = floatArray[iV++] * scale;
if (hasDeform) {
xL += deformVertices[iF++];
yL += deformVertices[iF++];
}
xG += (matrix.a * xL + matrix.c * yL + matrix.tx) * weight;
yG += (matrix.b * xL + matrix.d * yL + matrix.ty) * weight;
}
}
localVertices[lvi] = xG;
localVertices[lvi + 1] = -yG;
}
}
else if (hasDeform) {
const isSurface = this._parent._boneData.type !== BoneType.Bone;
const data = verticesData.data;
const intArray = data.intArray;
const floatArray = data.floatArray;
const vertexCount = intArray[verticesData.offset + BinaryOffset.MeshVertexCount];
let vertexOffset = intArray[verticesData.offset + BinaryOffset.MeshFloatOffset];
if (vertexOffset < 0) {
vertexOffset += 65536; // Fixed out of bouds bug.
}
for (let i = 0, l = vertexCount, lvi = 0; i < l; i ++, lvi += 4) {
const x = floatArray[vertexOffset + i*2] * scale + deformVertices[i*2];
const y = floatArray[vertexOffset + i*2 + 1] * scale + deformVertices[i*2 + 1];
if (isSurface) {
const matrix = this._parent._getGlobalTransformMatrix(x, y);
localVertices[lvi] = matrix.a * x + matrix.c * y + matrix.tx;
localVertices[lvi + 1] = -matrix.b * x + matrix.d * y + matrix.ty;
}
else {
localVertices[lvi] = x;
localVertices[lvi + 1] = -y;
}
}
}
if (weightData) {
this._identityTransform();
}
},
_identityTransform() {
let m = this._matrix.m;
m[0] = 1.0;
m[1] = 0.0;
m[4] = -0.0;
m[5] = -1.0;
m[12] = 0.0;
m[13] = 0.0;
this._worldMatrixDirty = true;
},
_updateTransform () {
let t = this._matrix;
let tm = t.m;
tm[0] = this.globalTransformMatrix.a;
tm[1] = this.globalTransformMatrix.b;
tm[4] = -this.globalTransformMatrix.c;
tm[5] = -this.globalTransformMatrix.d;
if (this._childArmature) {
tm[12] = this.globalTransformMatrix.tx;
tm[13] = this.globalTransformMatrix.ty;
} else {
tm[12] = this.globalTransformMatrix.tx - (this.globalTransformMatrix.a * this._pivotX - this.globalTransformMatrix.c * this._pivotY);
tm[13] = this.globalTransformMatrix.ty - (this.globalTransformMatrix.b * this._pivotX - this.globalTransformMatrix.d * this._pivotY);
}
this._worldMatrixDirty = true;
},
updateWorldMatrix () {
if (!this._armature) return;
var parentSlot = this._armature._parent;
if (parentSlot) {
parentSlot.updateWorldMatrix();
}
if (this._worldMatrixDirty) {
this.calculWorldMatrix();
var childArmature = this.childArmature;
if (!childArmature) return;
var slots = childArmature.getSlots();
for (var i = 0,n = slots.length; i < n; i++) {
var slot = slots[i];
if (slot) {
slot._worldMatrixDirty = true;
}
}
}
},
_mulMat (out, a, b) {
let am = a.m, bm = b.m, outm = out.m;
let aa=am[0], ab=am[1], ac=am[4], ad=am[5], atx=am[12], aty=am[13];
let ba=bm[0], bb=bm[1], bc=bm[4], bd=bm[5], btx=bm[12], bty=bm[13];
if (ab !== 0 || ac !== 0) {
outm[0] = ba * aa + bb * ac;
outm[1] = ba * ab + bb * ad;
outm[4] = bc * aa + bd * ac;
outm[5] = bc * ab + bd * ad;
outm[12] = aa * btx + ac * bty + atx;
outm[13] = ab * btx + ad * bty + aty;
}
else {
outm[0] = ba * aa;
outm[1] = bb * ad;
outm[4] = bc * aa;
outm[5] = bd * ad;
outm[12] = aa * btx + atx;
outm[13] = ad * bty + aty;
}
},
calculWorldMatrix () {
var parent = this._armature._parent;
if (parent) {
this._mulMat(this._worldMatrix ,parent._worldMatrix, this._matrix);
} else {
Mat4.copy(this._worldMatrix, this._matrix);
}
this._worldMatrixDirty = false;
}
});

View File

@@ -0,0 +1,110 @@
/****************************************************************************
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.
****************************************************************************/
dragonBones.CCTextureAtlasData = cc.Class({
extends: dragonBones.TextureAtlasData,
name: "dragonBones.CCTextureAtlasData",
properties: {
_renderTexture: {
default: null,
serializable: false
},
renderTexture: {
get () {
return this._renderTexture;
},
set (value) {
this._renderTexture = value;
if (value) {
for (let k in this.textures) {
let textureData = this.textures[k];
if (!textureData.spriteFrame) {
let rect = null;
if (textureData.rotated) {
rect = cc.rect(textureData.region.x, textureData.region.y,
textureData.region.height, textureData.region.width);
} else {
rect = cc.rect(textureData.region.x, textureData.region.y,
textureData.region.width, textureData.region.height);
}
let offset = cc.v2(0, 0);
let size = cc.size(rect.width, rect.height);
textureData.spriteFrame = new cc.SpriteFrame();
textureData.spriteFrame.setTexture(value, rect, false, offset, size);
}
}
} else {
for (let k in this.textures) {
let textureData = this.textures[k];
textureData.spriteFrame = null;
}
}
},
}
},
statics: {
toString: function () {
return "[class dragonBones.CCTextureAtlasData]";
}
},
_onClear: function () {
dragonBones.TextureAtlasData.prototype._onClear.call(this);
this.renderTexture = null;
},
createTexture : function() {
return dragonBones.BaseObject.borrowObject(dragonBones.CCTextureData);
}
});
dragonBones.CCTextureData = cc.Class({
extends: dragonBones.TextureData,
name: "dragonBones.CCTextureData",
properties: {
spriteFrame: {
default: null,
serializable: false
},
},
statics: {
toString: function () {
return "[class dragonBones.CCTextureData]";
}
},
_onClear: function () {
dragonBones.TextureData.prototype._onClear.call(this);
this.spriteFrame = null;
}
});

View File

@@ -0,0 +1,189 @@
/****************************************************************************
Copyright (c) 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.
****************************************************************************/
/**
* @module dragonBones
*/
let ArmatureCache = !CC_JSB && require('./ArmatureCache').sharedCache;
/**
* !#en The skeleton data of dragonBones.
* !#zh dragonBones 的 骨骼数据。
* @class DragonBonesAsset
* @extends Asset
*/
var DragonBonesAsset = cc.Class({
name: 'dragonBones.DragonBonesAsset',
extends: cc.Asset,
ctor () {
this.reset();
},
properties: {
_dragonBonesJson : '',
/**
* !#en See http://developer.egret.com/cn/github/egret-docs/DB/dbLibs/dataFormat/index.html
* !#zh 可查看 DragonBones 官方文档 http://developer.egret.com/cn/github/egret-docs/DB/dbLibs/dataFormat/index.html
* @property {string} dragonBonesJson
*/
dragonBonesJson : {
get: function () {
return this._dragonBonesJson;
},
set: function (value) {
this._dragonBonesJson = value;
this._dragonBonesJsonData = JSON.parse(value);
this.reset();
}
},
_nativeAsset: {
get () {
return this._buffer;
},
set (bin) {
this._buffer = bin.buffer || bin;
this.reset();
},
override: true
},
},
statics: {
preventDeferredLoadDependents: true
},
createNode: CC_EDITOR && function (callback) {
var node = new cc.Node(this.name);
var armatureDisplay = node.addComponent(dragonBones.ArmatureDisplay);
armatureDisplay.dragonAsset = this;
return callback(null, node);
},
reset () {
this._clear();
if (CC_EDITOR) {
this._armaturesEnum = null;
}
},
init (factory, atlasUUID) {
if (CC_EDITOR) {
this._factory = factory || new dragonBones.CCFactory();
} else {
this._factory = factory;
}
if (!this._dragonBonesJsonData && this.dragonBonesJson) {
this._dragonBonesJsonData = JSON.parse(this.dragonBonesJson);
}
let rawData = null;
if (this._dragonBonesJsonData) {
rawData = this._dragonBonesJsonData;
} else {
rawData = this._nativeAsset;
}
// If create by manual, uuid is empty.
if (!this._uuid) {
let dbData = this._factory.getDragonBonesDataByRawData(rawData);
if (dbData) {
this._uuid = dbData.name;
} else {
cc.warn('dragonbones name is empty');
}
}
let armatureKey = this._uuid + "#" + atlasUUID;
let dragonBonesData = this._factory.getDragonBonesData(armatureKey);
if (dragonBonesData) return armatureKey;
this._factory.parseDragonBonesData(rawData, armatureKey);
return armatureKey;
},
// EDITOR
getArmatureEnum: CC_EDITOR && function () {
if (this._armaturesEnum) {
return this._armaturesEnum;
}
this.init();
let dragonBonesData = this._factory.getDragonBonesDataByUUID(this._uuid);
if (dragonBonesData) {
var armatureNames = dragonBonesData.armatureNames;
var enumDef = {};
for (var i = 0; i < armatureNames.length; i++) {
var name = armatureNames[i];
enumDef[name] = i;
}
return this._armaturesEnum = cc.Enum(enumDef);
}
return null;
},
getAnimsEnum: CC_EDITOR && function (armatureName) {
this.init();
let dragonBonesData = this._factory.getDragonBonesDataByUUID(this._uuid);
if (dragonBonesData) {
var armature = dragonBonesData.getArmature(armatureName);
if (!armature) {
return null;
}
var enumDef = { '<None>': 0 };
var anims = armature.animations;
var i = 0;
for (var animName in anims) {
if (anims.hasOwnProperty(animName)) {
enumDef[animName] = i + 1;
i++;
}
}
return cc.Enum(enumDef);
}
return null;
},
_clear () {
if (this._factory) {
ArmatureCache.resetArmature(this._uuid);
this._factory.removeDragonBonesDataByUUID(this._uuid, true);
}
},
destroy () {
this._clear();
this._super();
},
});
dragonBones.DragonBonesAsset = module.exports = DragonBonesAsset;

View File

@@ -0,0 +1,132 @@
/****************************************************************************
Copyright (c) 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.
****************************************************************************/
/**
* @module dragonBones
*/
let ArmatureCache = !CC_JSB && require('./ArmatureCache').sharedCache;
/**
* !#en The skeleton atlas data of dragonBones.
* !#zh dragonBones 的骨骼纹理数据。
* @class DragonBonesAtlasAsset
* @extends Asset
*/
var DragonBonesAtlasAsset = cc.Class({
name: 'dragonBones.DragonBonesAtlasAsset',
extends: cc.Asset,
ctor () {
this._clear();
},
properties: {
_atlasJson : '',
/**
* @property {string} atlasJson
*/
atlasJson: {
get: function () {
return this._atlasJson;
},
set: function (value) {
this._atlasJson = value;
this._atlasJsonData = JSON.parse(this.atlasJson);
this._clear();
}
},
_texture: {
default: null,
type: cc.Texture2D,
formerlySerializedAs: 'texture'
},
/**
* @property {Texture2D} texture
*/
texture: {
get () {
return this._texture;
},
set (value) {
this._texture = value;
this._clear();
}
},
_textureAtlasData: null,
},
statics: {
preventDeferredLoadDependents: true
},
createNode: CC_EDITOR && function (callback) {
var node = new cc.Node(this.name);
var armatureDisplay = node.addComponent(dragonBones.ArmatureDisplay);
armatureDisplay.dragonAtlasAsset = this;
return callback(null, node);
},
init (factory) {
this._factory = factory;
if (!this._atlasJsonData) {
this._atlasJsonData = JSON.parse(this.atlasJson);
}
let atlasJsonObj = this._atlasJsonData;
// If create by manual, uuid is empty.
this._uuid = this._uuid || atlasJsonObj.name;
if (this._textureAtlasData) {
factory.addTextureAtlasData(this._textureAtlasData, this._uuid);
}
else {
this._textureAtlasData = factory.parseTextureAtlasData(atlasJsonObj, this.texture, this._uuid);
}
},
_clear () {
if (CC_JSB) return;
if (this._factory) {
ArmatureCache.resetArmature(this._uuid);
this._factory.removeTextureAtlasData(this._uuid, true);
this._factory.removeDragonBonesDataByUUID(this._uuid, true);
}
this._textureAtlasData = null;
},
destroy () {
this._clear();
this._super();
},
});
dragonBones.DragonBonesAtlasAsset = module.exports = DragonBonesAtlasAsset;

View File

@@ -0,0 +1,90 @@
/****************************************************************************
Copyright (c) 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.
****************************************************************************/
const Fs = require('fire-fs');
const Path = require('fire-path');
const DRAGONBONES_ENCODING = { encoding: 'utf-8' };
const CustomAssetMeta = Editor.metas['custom-asset'];
class DragonBonesAtlasMeta extends CustomAssetMeta {
constructor (assetdb) {
super(assetdb);
}
static version () { return '1.0.3'; }
static defaultType () {
return 'dragonbones-atlas';
}
static validate (assetpath) {
try {
const json = Fs.readJsonSync(assetpath);
return typeof json.imagePath === 'string' && Array.isArray(json.SubTexture);
}
catch (e) {
return false;
}
}
postImport (fspath, cb) {
Fs.readFile(fspath, DRAGONBONES_ENCODING, (err, data) => {
if (err) {
return cb(err);
}
var json;
try {
json = JSON.parse(data);
}
catch (e) {
return cb(e);
}
// parse the depended texture
var imgPath = Path.resolve(Path.dirname(fspath), json.imagePath);
var textureUUID = this._assetdb.fspathToUuid(imgPath);
if (textureUUID) {
console.log('UUID is initialized for "%s".', imgPath);
}
else if (!Fs.existsSync(imgPath)) {
Editor.error('Can not find texture "%s" for atlas "%s"', json.imagePath, fspath);
}
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".', json.imagePath);
}
var asset = new dragonBones.DragonBonesAtlasAsset();
asset.name = Path.basenameNoExt(fspath);
asset.atlasJson = data;
asset.texture = Editor.serialize.asAsset(textureUUID);
this._assetdb.saveAssetToLibrary(this.uuid, asset);
cb();
});
}
}
module.exports = DragonBonesAtlasMeta;

View File

@@ -0,0 +1,70 @@
/****************************************************************************
Copyright (c) 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.
****************************************************************************/
const Fs = require('fire-fs');
const Path = require('fire-path');
const DRAGONBONES_ENCODING = { encoding: 'utf-8' };
const CustomAssetMeta = Editor.metas['custom-asset'];
class DragonBonesMeta extends CustomAssetMeta {
constructor (assetdb) {
super(assetdb);
}
static version () { return '1.0.3'; }
static defaultType () {
return 'dragonbones';
}
static validate (assetpath) {
var json;
var text = Fs.readFileSync(assetpath, 'utf8');
try {
json = JSON.parse(text);
}
catch (e) {
return false;
}
return Array.isArray(json.armature);
}
import (fspath, cb) {
Fs.readFile(fspath, DRAGONBONES_ENCODING, (err, data) => {
if (err) {
return cb(err);
}
var asset = new dragonBones.DragonBonesAsset();
asset.name = Path.basenameNoExt(fspath);
asset.dragonBonesJson = data;
this._assetdb.saveAssetToLibrary(this.uuid, asset);
cb();
});
}
}
module.exports = DragonBonesMeta;

View File

@@ -0,0 +1,171 @@
/****************************************************************************
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 DragonBones, all classes, functions,
* properties and constants of DragonBones are defined in this namespace
* !#zh
* DragonBones 的全局的命名空间,
* 与 DragonBones 相关的所有的类,函数,属性,常量都在这个命名空间中定义。
* @module dragonBones
* @main dragonBones
*/
/*
* Reference:
* http://dragonbones.com/cn/index.html
*/
var _global = typeof window === 'undefined' ? global : window;
if (!CC_NATIVERENDERER) {
_global.dragonBones = require('./lib/dragonBones');
}
if (_global.dragonBones !== undefined) {
/**
* !#en
* The global time scale of DragonBones.
* !#zh
* DragonBones 全局时间缩放率。
* @example
* dragonBones.timeScale = 0.8;
*/
dragonBones._timeScale = 1.0;
Object.defineProperty(dragonBones, 'timeScale', {
get () {
return this._timeScale;
},
set (value) {
this._timeScale = value;
let factory = this.CCFactory.getInstance();
factory._dragonBones.clock.timeScale = value;
},
configurable: true,
});
dragonBones.DisplayType = {
Image : 0,
Armature : 1,
Mesh : 2
};
dragonBones.ArmatureType = {
Armature : 0,
MovieClip : 1,
Stage : 2
};
dragonBones.ExtensionType = {
FFD : 0,
AdjustColor : 10,
BevelFilter : 11,
BlurFilter : 12,
DropShadowFilter : 13,
GlowFilter : 14,
GradientBevelFilter : 15,
GradientGlowFilter : 16
};
dragonBones.EventType = {
Frame : 0,
Sound : 1
};
dragonBones.ActionType = {
Play : 0,
Stop : 1,
GotoAndPlay : 2,
GotoAndStop : 3,
FadeIn : 4,
FadeOut : 5
};
dragonBones.AnimationFadeOutMode = {
None : 0,
SameLayer : 1,
SameGroup : 2,
SameLayerAndGroup : 3,
All : 4
};
dragonBones.BinaryOffset = {
WeigthBoneCount: 0,
WeigthFloatOffset: 1,
WeigthBoneIndices: 2,
MeshVertexCount: 0,
MeshTriangleCount: 1,
MeshFloatOffset: 2,
MeshWeightOffset: 3,
MeshVertexIndices: 4,
TimelineScale: 0,
TimelineOffset: 1,
TimelineKeyFrameCount: 2,
TimelineFrameValueCount: 3,
TimelineFrameValueOffset: 4,
TimelineFrameOffset: 5,
FramePosition: 0,
FrameTweenType: 1,
FrameTweenEasingOrCurveSampleCount: 2,
FrameCurveSamples: 3,
DeformMeshOffset: 0,
DeformCount: 1,
DeformValueCount: 2,
DeformValueOffset: 3,
DeformFloatOffset: 4
};
dragonBones.BoneType = {
Bone: 0,
Surface: 1
};
if (!CC_EDITOR || !Editor.isMainProcess) {
if (!CC_NATIVERENDERER) {
require('./CCFactory');
require('./CCSlot');
require('./CCTextureData');
require('./CCArmatureDisplay');
require('./ArmatureCache');
}
// require the component for dragonbones
require('./DragonBonesAsset');
require('./DragonBonesAtlasAsset');
require('./ArmatureDisplay');
require('./webgl-assembler');
} else {
require('./DragonBonesAsset');
require('./DragonBonesAtlasAsset');
}
}

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,377 @@
/****************************************************************************
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';
import Mat4 from '../../cocos2d/core/value-types/mat4';
const Armature = require('./ArmatureDisplay');
const RenderFlow = require('../../cocos2d/core/renderer/render-flow');
const gfx = cc.gfx;
const NEED_COLOR = 0x01;
const NEED_BATCH = 0x10;
let _boneColor = cc.color(255, 0, 0, 255);
let _slotColor = cc.color(0, 0, 255, 255);
let _originColor = cc.color(0, 255, 0, 255);
let _nodeR, _nodeG, _nodeB, _nodeA,
_premultipliedAlpha, _multiply,
_mustFlush, _buffer, _node,
_renderer, _comp,
_vfOffset, _indexOffset, _vertexOffset,
_vertexCount, _indexCount,
_x, _y, _c, _r, _g, _b, _a, _handleVal,
_m00, _m04, _m12,
_m01, _m05, _m13;
function _getSlotMaterial (tex, blendMode) {
if(!tex)return null;
let src, dst;
switch (blendMode) {
case 1://additive
src = _premultipliedAlpha ? cc.macro.ONE : cc.macro.SRC_ALPHA;
dst = cc.macro.ONE;
break;
case 10://multiply
src = cc.macro.DST_COLOR;
dst = cc.macro.ONE_MINUS_SRC_ALPHA;
break;
case 12://screen
src = cc.macro.ONE;
dst = cc.macro.ONE_MINUS_SRC_COLOR;
break;
case 0://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;
}
let materialCache = _comp._materialCache;
// The key use to find corresponding material
let key = tex.getId() + src + dst + useModel;
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.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, parentOpacity) {
_a = color.a * parentOpacity * _nodeA;
_multiply = _premultipliedAlpha? _a / 255.0 : 1.0;
_r = color.r * _nodeR * _multiply;
_g = color.g * _nodeG * _multiply;
_b = color.b * _nodeB * _multiply;
_c = ((_a<<24) >>> 0) + (_b<<16) + (_g<<8) + _r;
}
export default class ArmatureAssembler extends Assembler {
updateRenderData (comp, batchData) {}
realTimeTraverse (armature, parentMat, parentOpacity) {
let slots = armature._slots;
let vbuf, ibuf, uintbuf;
let material;
let vertices, indices;
let slotColor;
let slot;
let slotMat;
let slotMatm;
let offsetInfo;
for (let i = 0, l = slots.length; i < l; i++) {
slot = slots[i];
slotColor = slot._color;
if (!slot._visible || !slot._displayData) continue;
if (parentMat) {
slot._mulMat(slot._worldMatrix, parentMat, slot._matrix);
} else {
Mat4.copy(slot._worldMatrix, slot._matrix);
}
if (slot.childArmature) {
this.realTimeTraverse(slot.childArmature, slot._worldMatrix, parentOpacity * slotColor.a / 255);
continue;
}
material = _getSlotMaterial(slot.getTexture(), slot._blendMode);
if (!material) {
continue;
}
if (_mustFlush || material.getHash() !== _renderer.material.getHash()) {
_mustFlush = false;
_renderer._flush();
_renderer.node = _node;
_renderer.material = material;
}
_handleColor(slotColor, parentOpacity);
slotMat = slot._worldMatrix;
slotMatm = slotMat.m;
vertices = slot._localVertices;
_vertexCount = vertices.length >> 2;
indices = slot._indices;
_indexCount = indices.length;
offsetInfo = _buffer.request(_vertexCount, _indexCount);
_indexOffset = offsetInfo.indiceOffset;
_vfOffset = offsetInfo.byteOffset >> 2;
_vertexOffset = offsetInfo.vertexOffset;
vbuf = _buffer._vData;
ibuf = _buffer._iData;
uintbuf = _buffer._uintVData;
_m00 = slotMatm[0];
_m04 = slotMatm[4];
_m12 = slotMatm[12];
_m01 = slotMatm[1];
_m05 = slotMatm[5];
_m13 = slotMatm[13];
for (let vi = 0, vl = vertices.length; vi < vl;) {
_x = vertices[vi++];
_y = vertices[vi++];
vbuf[_vfOffset++] = _x * _m00 + _y * _m04 + _m12; // x
vbuf[_vfOffset++] = _x * _m01 + _y * _m05 + _m13; // y
vbuf[_vfOffset++] = vertices[vi++]; // u
vbuf[_vfOffset++] = vertices[vi++]; // v
uintbuf[_vfOffset++] = _c; // color
}
for (let ii = 0, il = indices.length; ii < il; ii ++) {
ibuf[_indexOffset++] = _vertexOffset + indices[ii];
}
}
}
cacheTraverse (frame, parentMat) {
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 frameVFOffset = 0, frameIndexOffset = 0, segVFCount = 0;
if (parentMat) {
let parentMatm = parentMat.m;
_m00 = parentMatm[0];
_m01 = parentMatm[1];
_m04 = parentMatm[4];
_m05 = parentMatm[5];
_m12 = parentMatm[12];
_m13 = parentMatm[13];
}
let justTranslate = _m00 === 1 && _m01 === 0 && _m04 === 0 && _m05 === 1;
let needBatch = (_handleVal & NEED_BATCH);
let calcTranslate = needBatch && justTranslate;
let colorOffset = 0;
let colors = frame.colors;
let nowColor = colors[colorOffset++];
let maxVFOffset = nowColor.vfOffset;
_handleColor(nowColor, 1.0);
for (let i = 0, n = segments.length; i < n; i++) {
let segInfo = segments[i];
material = _getSlotMaterial(segInfo.tex, segInfo.blendMode);
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 += 5) {
vbuf[ii] += _m12;
vbuf[ii + 1] += _m13;
}
} else if (needBatch) {
for (let ii = _vfOffset, il = _vfOffset + segVFCount; ii < il; ii += 5) {
_x = vbuf[ii];
_y = vbuf[ii + 1];
vbuf[ii] = _x * _m00 + _y * _m04 + _m12;
vbuf[ii + 1] = _x * _m01 + _y * _m05 + _m13;
}
}
if ( !(_handleVal & NEED_COLOR) ) continue;
// handle color
let frameColorOffset = frameVFOffset - segVFCount;
for (let ii = _vfOffset + 4, il = _vfOffset + 4 + segVFCount; ii < il; ii += 5, frameColorOffset += 5) {
if (frameColorOffset >= maxVFOffset) {
nowColor = colors[colorOffset++];
_handleColor(nowColor, 1.0);
maxVFOffset = nowColor.vfOffset;
}
uintbuf[ii] = _c;
}
}
}
fillBuffers (comp, renderer) {
comp.node._renderFlag |= RenderFlow.FLAG_UPDATE_RENDER_DATA;
let armature = comp._armature;
if (!armature) return;
// Init temp var.
_mustFlush = true;
_premultipliedAlpha = comp.premultipliedAlpha;
_node = comp.node;
_buffer = renderer._meshBuffer;
_renderer = renderer;
_comp = comp;
_handleVal = 0;
let nodeColor = _node._color;
_nodeR = nodeColor.r / 255;
_nodeG = nodeColor.g / 255;
_nodeB = nodeColor.b / 255;
_nodeA = nodeColor.a / 255;
if (nodeColor._val !== 0xffffffff) {
_handleVal |= NEED_COLOR;
}
let worldMat = undefined;
if (_comp.enableBatch) {
worldMat = _node._worldMatrix;
_mustFlush = false;
_handleVal |= NEED_BATCH;
}
if (comp.isAnimationCached()) {
// Traverse input assembler.
this.cacheTraverse(comp._curFrame, worldMat);
} else {
// Traverse all armature.
this.realTimeTraverse(armature, worldMat, 1.0);
let graphics = comp._debugDraw;
if (comp.debugBones && graphics) {
graphics.clear();
graphics.lineWidth = 5;
graphics.strokeColor = _boneColor;
graphics.fillColor = _slotColor; // Root bone color is same as slot color.
let bones = armature.getBones();
for (let i = 0, l = bones.length; i < l; i++) {
let bone = bones[i];
let boneLength = Math.max(bone.boneData.length, 5);
let startX = bone.globalTransformMatrix.tx;
let startY = bone.globalTransformMatrix.ty;
let endX = startX + bone.globalTransformMatrix.a * boneLength;
let endY = startY + bone.globalTransformMatrix.b * boneLength;
graphics.moveTo(startX, startY);
graphics.lineTo(endX, endY);
graphics.stroke();
// Bone origins.
graphics.circle(startX, startY, Math.PI * 2);
graphics.fill();
if (i === 0) {
graphics.fillColor = _originColor;
}
}
}
}
// sync attached node matrix
renderer.worldMatDirty++;
comp.attachUtil._syncAttachedNode();
// Clear temp var.
_node = undefined;
_buffer = undefined;
_renderer = undefined;
_comp = undefined;
}
postFillBuffers (comp, renderer) {
renderer.worldMatDirty--;
}
}
Assembler.register(Armature, ArmatureAssembler);

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;