lujun 973434cd71 1、修正spine动画引起的渲染问题
2、sortinggroup组件只在当前节点和其子节点有效,其他节点仍然使用节点树遍历
2023-03-21 22:23:01 +08:00

654 lines
22 KiB
TypeScript

// @ts-ignore
const gfx = cc.gfx;
// @ts-ignore
const spine = sp.spine;
// @ts-ignore
const VFOneColor = gfx.VertexFormat.vfmtPosUvColor;
// @ts-ignore
const VFTwoColor = gfx.VertexFormat.vfmtPosUvTwoColor;
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;
// @ts-ignore
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, null);
}
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;
}
// @ts-ignore
sp.Skeleton.__assembler__.fillVertices = function (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;
}
}
}
}
}
// @ts-ignore
sp.Skeleton.__assembler__.realTimeTraverse = function (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;
}
}
}
}
// @ts-ignore
sp.Skeleton.__assembler__.cacheTraverse = function (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;
}
}
}
// @ts-ignore
sp.Skeleton.__assembler__.fillBuffers = function (comp, renderer) {
let node = comp.node;
// @ts-ignore
node._renderFlag |= cc.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();
}
// Clear temp var.
_node = undefined;
_buffer = undefined;
_renderer = undefined;
_comp = undefined;
_vertexEffect = null;
}