CCSprite的类型触发切换Assem
fillType : { get () { return this._fillType; }, set (value) { if (value !== this._fillType) { this._fillType = value; this.setVertsDirty(); this._resetAssembler();// 属性的更新触发了assembler重置 } }, type: FillType, tooltip: CC_DEV && 'i18n:COMPONENT.sprite.fill_type' },
- CCRenderComponent.js
_resetAssembler () { Assembler.init(this);// 会触发红心绑定Assembler this._updateColor(); this.setVertsDirty(); },
Assembler基类的实现
- cocos2d\core\renderer\assembler.js
export default class Assembler { constructor () { this._extendNative && this._extendNative(); } init (renderComp) { this._renderComp = renderComp; } updateRenderData (comp) { } fillBuffers (comp, renderer) { } getVfmt () { return vfmtPosUvColor; } } Assembler.init = function (renderComp) { let renderCompCtor = renderComp.constructor; let assemblerCtor = renderCompCtor.__assembler__; while (!assemblerCtor) { renderCompCtor = renderCompCtor.$super; if (!renderCompCtor) { cc.warn(`Can not find assembler for render component : [${cc.js.getClassName(renderComp)}]`); return; } assemblerCtor = renderCompCtor.__assembler__; } if (assemblerCtor.getConstructor) { assemblerCtor = assemblerCtor.getConstructor(renderComp); } if (!renderComp._assembler || renderComp._assembler.constructor !== assemblerCtor) { let assembler = assemblerPool.get(assemblerCtor); assembler.init(renderComp); renderComp._assembler = assembler; } };
注册spriteAssembler的地方
- cocos2d\core\renderer\webgl\assemblers\sprite\index.js
js
复制代码
import Simple3D from "./3d/simple"; import Sliced3D from "./3d/sliced"; let ctor = { getConstructor(sprite) { let is3DNode = sprite.node.is3DNode; let ctor = is3DNode ? Simple3D : Simple; switch (sprite.type) { // 根据不同的类型进行不同的assembler的获取 case Type.SLICED: ctor = is3DNode ? Sliced3D : Sliced; break; } return ctor; }, }; Assembler.register(cc.Sprite, ctor);
Sprite使用的Simple
- cocos2d\core\renderer\webgl\assemblers\sprite\2d\simple.js
import Assembler2D from '../../../../assembler-2d'; export default class SimpleSpriteAssembler extends Assembler2D { updateRenderData (sprite) { this.packToDynamicAtlas(sprite, sprite._spriteFrame); if (sprite._vertsDirty) { this.updateUVs(sprite); this.updateVerts(sprite); sprite._vertsDirty = false; } } updateUVs (sprite) { let uv = sprite._spriteFrame.uv; let uvOffset = this.uvOffset; let floatsPerVert = this.floatsPerVert; let verts = this._renderData.vDatas[0]; for (let i = 0; i < 4; i++) { let srcOffset = i * 2; let dstOffset = floatsPerVert * i + uvOffset; verts[dstOffset] = uv[srcOffset]; verts[dstOffset + 1] = uv[srcOffset + 1]; } } updateVerts (sprite) { let node = sprite.node, cw = node.width, ch = node.height, appx = node.anchorX * cw, appy = node.anchorY * ch, l, b, r, t; if (sprite.trim) { l = -appx; b = -appy; r = cw - appx; t = ch - appy; } else { let frame = sprite.spriteFrame, ow = frame._originalSize.width, oh = frame._originalSize.height, rw = frame._rect.width, rh = frame._rect.height, offset = frame._offset, scaleX = cw / ow, scaleY = ch / oh; let trimLeft = offset.x + (ow - rw) / 2; let trimRight = offset.x - (ow - rw) / 2; let trimBottom = offset.y + (oh - rh) / 2; let trimTop = offset.y - (oh - rh) / 2; l = trimLeft * scaleX - appx; b = trimBottom * scaleY - appy; r = cw + trimRight * scaleX - appx; t = ch + trimTop * scaleY - appy; } let local = this._local; local[0] = l; local[1] = b; local[2] = r; local[3] = t; this.updateWorldVerts(sprite); } }
Assembler2D
- cocos2d\core\renderer\assembler-2d.js
import Assembler from './assembler'; import dynamicAtlasManager from './utils/dynamic-atlas/manager'; import RenderData from './webgl/render-data'; export default class Assembler2D extends Assembler { constructor () { super(); this._renderData = new RenderData(); this._renderData.init(this); this.initData(); this.initLocal(); } get verticesFloats () { return this.verticesCount * this.floatsPerVert; } initData () { let data = this._renderData; data.createQuadData(0, this.verticesFloats, this.indicesCount); } initLocal () { this._local = []; this._local.length = 4; } updateColor (comp, color) { let uintVerts = this._renderData.uintVDatas[0]; if (!uintVerts) return; color = color != null ? color : comp.node.color._val; let floatsPerVert = this.floatsPerVert; let colorOffset = this.colorOffset; for (let i = colorOffset, l = uintVerts.length; i < l; i += floatsPerVert) { uintVerts[i] = color; } } getBuffer () { return cc.renderer._handle._meshBuffer; } updateWorldVerts (comp) { let local = this._local; let verts = this._renderData.vDatas[0]; let matrix = comp.node._worldMatrix; let matrixm = matrix.m, a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5], tx = matrixm[12], ty = matrixm[13]; let vl = local[0], vr = local[2], vb = local[1], vt = local[3]; let floatsPerVert = this.floatsPerVert; let vertexOffset = 0; let justTranslate = a === 1 && b === 0 && c === 0 && d === 1; if (justTranslate) { // left bottom verts[vertexOffset] = vl + tx; verts[vertexOffset + 1] = vb + ty; vertexOffset += floatsPerVert; // right bottom verts[vertexOffset] = vr + tx; verts[vertexOffset + 1] = vb + ty; vertexOffset += floatsPerVert; // left top verts[vertexOffset] = vl + tx; verts[vertexOffset + 1] = vt + ty; vertexOffset += floatsPerVert; // right top verts[vertexOffset] = vr + tx; verts[vertexOffset + 1] = vt + ty; } else { let al = a * vl, ar = a * vr, bl = b * vl, br = b * vr, cb = c * vb, ct = c * vt, db = d * vb, dt = d * vt; // left bottom verts[vertexOffset] = al + cb + tx; verts[vertexOffset + 1] = bl + db + ty; vertexOffset += floatsPerVert; // right bottom verts[vertexOffset] = ar + cb + tx; verts[vertexOffset + 1] = br + db + ty; vertexOffset += floatsPerVert; // left top verts[vertexOffset] = al + ct + tx; verts[vertexOffset + 1] = bl + dt + ty; vertexOffset += floatsPerVert; // right top verts[vertexOffset] = ar + ct + tx; verts[vertexOffset + 1] = br + dt + ty; } } fillBuffers (comp, renderer) { if (renderer.worldMatDirty) { this.updateWorldVerts(comp); } let renderData = this._renderData; let vData = renderData.vDatas[0]; let iData = renderData.iDatas[0]; let buffer = this.getBuffer(renderer); let offsetInfo = buffer.request(this.verticesCount, this.indicesCount); // buffer data may be realloc, need get reference after request. // fill vertices let vertexOffset = offsetInfo.byteOffset >> 2, vbuf = buffer._vData; if (vData.length + vertexOffset > vbuf.length) { vbuf.set(vData.subarray(0, vbuf.length - vertexOffset), vertexOffset); } else { vbuf.set(vData, vertexOffset); } // fill indices let ibuf = buffer._iData, indiceOffset = offsetInfo.indiceOffset, vertexId = offsetInfo.vertexOffset; for (let i = 0, l = iData.length; i < l; i++) { ibuf[indiceOffset++] = vertexId + iData[i]; } } packToDynamicAtlas (comp, frame) { if (CC_TEST) return; if (!frame._original && dynamicAtlasManager && frame._texture.packable && frame._texture.loaded) { let packedFrame = dynamicAtlasManager.insertSpriteFrame(frame); if (packedFrame) { frame._setDynamicAtlasFrame(packedFrame); } } let material = comp._materials[0]; if (!material) return; if (material.getProperty('texture') !== frame._texture._texture) { // texture was packed to dynamic atlas, should update uvs comp._vertsDirty = true; comp._updateMaterial(); } } } cc.js.addon(Assembler2D.prototype, { floatsPerVert: 5, verticesCount: 4, indicesCount: 6, uvOffset: 2, colorOffset: 4, }); cc.Assembler2D = Assembler2D;