mirror of
https://github.com/smallmain/cocos-enhance-kit.git
synced 2026-01-11 04:16:53 +00:00
初始化
This commit is contained in:
167
engine/extensions/ccpool/CCNodePool.js
Normal file
167
engine/extensions/ccpool/CCNodePool.js
Normal 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;
|
||||
521
engine/extensions/dragonbones/ArmatureCache.js
Normal file
521
engine/extensions/dragonbones/ArmatureCache.js
Normal 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;
|
||||
1156
engine/extensions/dragonbones/ArmatureDisplay.js
Normal file
1156
engine/extensions/dragonbones/ArmatureDisplay.js
Normal file
File diff suppressed because it is too large
Load Diff
506
engine/extensions/dragonbones/AttachUtil.js
Normal file
506
engine/extensions/dragonbones/AttachUtil.js
Normal 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;
|
||||
125
engine/extensions/dragonbones/CCArmatureDisplay.js
Normal file
125
engine/extensions/dragonbones/CCArmatureDisplay.js
Normal 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);
|
||||
}
|
||||
////////////////////////////////////
|
||||
|
||||
});
|
||||
187
engine/extensions/dragonbones/CCFactory.js
Normal file
187
engine/extensions/dragonbones/CCFactory.js
Normal 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];
|
||||
}
|
||||
}
|
||||
});
|
||||
383
engine/extensions/dragonbones/CCSlot.js
Normal file
383
engine/extensions/dragonbones/CCSlot.js
Normal 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;
|
||||
}
|
||||
});
|
||||
110
engine/extensions/dragonbones/CCTextureData.js
Normal file
110
engine/extensions/dragonbones/CCTextureData.js
Normal 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;
|
||||
}
|
||||
});
|
||||
189
engine/extensions/dragonbones/DragonBonesAsset.js
Normal file
189
engine/extensions/dragonbones/DragonBonesAsset.js
Normal 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;
|
||||
132
engine/extensions/dragonbones/DragonBonesAtlasAsset.js
Normal file
132
engine/extensions/dragonbones/DragonBonesAtlasAsset.js
Normal 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;
|
||||
@@ -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;
|
||||
70
engine/extensions/dragonbones/editor/dragonbones-meta.js
Normal file
70
engine/extensions/dragonbones/editor/dragonbones-meta.js
Normal 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;
|
||||
171
engine/extensions/dragonbones/index.js
Normal file
171
engine/extensions/dragonbones/index.js
Normal 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');
|
||||
}
|
||||
|
||||
}
|
||||
7477
engine/extensions/dragonbones/lib/dragonBones.d.ts
vendored
Normal file
7477
engine/extensions/dragonbones/lib/dragonBones.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
14985
engine/extensions/dragonbones/lib/dragonBones.js
Normal file
14985
engine/extensions/dragonbones/lib/dragonBones.js
Normal file
File diff suppressed because it is too large
Load Diff
377
engine/extensions/dragonbones/webgl-assembler.js
Normal file
377
engine/extensions/dragonbones/webgl-assembler.js
Normal 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);
|
||||
429
engine/extensions/spine/AttachUtil.js
Normal file
429
engine/extensions/spine/AttachUtil.js
Normal 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;
|
||||
1392
engine/extensions/spine/Skeleton.js
Normal file
1392
engine/extensions/spine/Skeleton.js
Normal file
File diff suppressed because it is too large
Load Diff
BIN
engine/extensions/spine/editor/spine-asset.png
Normal file
BIN
engine/extensions/spine/editor/spine-asset.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
259
engine/extensions/spine/editor/spine-meta.js
Normal file
259
engine/extensions/spine/editor/spine-meta.js
Normal 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;
|
||||
153
engine/extensions/spine/index.js
Normal file
153
engine/extensions/spine/index.js
Normal 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
|
||||
*/
|
||||
27
engine/extensions/spine/lib/LICENSE
Normal file
27
engine/extensions/spine/lib/LICENSE
Normal 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
1331
engine/extensions/spine/lib/spine.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
8174
engine/extensions/spine/lib/spine.js
Normal file
8174
engine/extensions/spine/lib/spine.js
Normal file
File diff suppressed because it is too large
Load Diff
648
engine/extensions/spine/skeleton-cache.js
Normal file
648
engine/extensions/spine/skeleton-cache.js
Normal 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;
|
||||
331
engine/extensions/spine/skeleton-data.js
Normal file
331
engine/extensions/spine/skeleton-data.js
Normal 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;
|
||||
53
engine/extensions/spine/skeleton-texture.js
Normal file
53
engine/extensions/spine/skeleton-texture.js
Normal 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() {}
|
||||
});
|
||||
689
engine/extensions/spine/spine-assembler.js
Normal file
689
engine/extensions/spine/spine-assembler.js
Normal 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);
|
||||
42
engine/extensions/spine/track-entry-listeners.js
Normal file
42
engine/extensions/spine/track-entry-listeners.js
Normal 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;
|
||||
138
engine/extensions/spine/vertex-effect-delegate.js
Normal file
138
engine/extensions/spine/vertex-effect-delegate.js
Normal 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;
|
||||
Reference in New Issue
Block a user