UNPKG

@senspark/ee

Version:

utility library for cocos creator

218 lines (184 loc) 7.32 kB
import assert = require('assert'); const { ccclass, disallowMultiple, executeInEditMode, menu } = cc._decorator; const assembler = { useModel: false, createData(sprite: cc.Sprite): any { const renderData = sprite.requestRenderData(); // 0-4 for local verts // 5-20 for world verts renderData.dataLength = 20; renderData.vertexCount = 16; renderData.indiceCount = 54; return renderData; }, updateRenderData(sprite: cc.Sprite, batchData: any): void { const frame = sprite.spriteFrame; const dynamicAtlasManager = (cc as any).dynamicAtlasManager; // TODO: Material API design and export from editor could affect the material activation process // need to update the logic here if (frame) { if (!(frame as any)._original && dynamicAtlasManager) { dynamicAtlasManager.insertSpriteFrame(frame); } if (sprite._material._texture !== (frame as any)._texture) { (sprite as any)._activateMaterial(); } } const renderData = sprite._renderData; if (renderData && frame) { const vertDirty = renderData.vertDirty; if (vertDirty) { this.updateVerts(sprite); this.updateWorldVerts(sprite); } } }, updateVerts(sprite: cc.Sprite): void { const renderData = sprite._renderData; const data = renderData._data; const node = sprite.node; const width = node.width; const height = node.height; const appx = node.anchorX * width; const appy = node.anchorY * height; const frame = sprite.spriteFrame; const leftWidth = frame.insetLeft; const rightWidth = frame.insetRight; const topHeight = frame.insetTop; const bottomHeight = frame.insetBottom; let sizableWidth = width - leftWidth - rightWidth; let sizableHeight = height - topHeight - bottomHeight; let xScale = width / (leftWidth + rightWidth); let yScale = height / (topHeight + bottomHeight); xScale = (isNaN(xScale) || xScale > 1) ? 1 : xScale; yScale = (isNaN(yScale) || yScale > 1) ? 1 : yScale; sizableWidth = sizableWidth < 0 ? 0 : sizableWidth; sizableHeight = sizableHeight < 0 ? 0 : sizableHeight; data[0].x = -appx; data[0].y = -appy; data[1].x = leftWidth * xScale - appx; data[1].y = bottomHeight * yScale - appy; data[2].x = data[1].x + sizableWidth; data[2].y = data[1].y + sizableHeight; data[3].x = width - appx; data[3].y = height - appy; renderData.vertDirty = false; }, fillBuffers(sprite: cc.Sprite, renderer: any): void { if (renderer.worldMatDirty) { this.updateWorldVerts(sprite); } const renderData = sprite._renderData; const data = renderData._data; const buffer = renderer._meshBuffer; let vertexOffset = buffer.byteOffset >> 2; const vertexCount = renderData.vertexCount; let indiceOffset = buffer.indiceOffset; const vertexId = buffer.vertexOffset; // Recalculate uv sliced if needed. const frame = sprite.spriteFrame as any; const insetL = frame.insetLeft; const insetR = frame.insetRight; const insetT = frame.insetTop; const insetB = frame.insetBottom; const sizableWidth = sprite.node.width - insetL - insetR; const sizableHeight = sprite.node.height - insetT - insetB; const oldInsets = [...frame._capInsets]; let needRecalculation = false; if (sizableWidth < 0) { const insetWidth = insetL + insetR; frame._capInsets[0] += sizableWidth * insetL / insetWidth; frame._capInsets[2] += sizableWidth * insetR / insetWidth; needRecalculation = true; } if (sizableHeight < 0) { const insetHeight = insetT + insetB; frame._capInsets[1] += sizableHeight * insetT / insetHeight; frame._capInsets[3] += sizableHeight * insetB / insetHeight; needRecalculation = true; } const oldUvSliced = []; if (needRecalculation) { oldUvSliced.push(...frame.uvSliced); frame._calculateSlicedUV(); } const uvSliced = frame.uvSliced; buffer.request(vertexCount, renderData.indiceCount); // buffer data may be realloc, need get reference after request. const vbuf = buffer._vData; const ibuf = buffer._iData; for (let i = 4; i < 20; ++i) { const vert = data[i]; const uvs = uvSliced[i - 4]; vbuf[vertexOffset++] = vert.x; vbuf[vertexOffset++] = vert.y; vbuf[vertexOffset++] = uvs.u; vbuf[vertexOffset++] = uvs.v; } for (let r = 0; r < 3; ++r) { for (let c = 0; c < 3; ++c) { const start = vertexId + r * 4 + c; ibuf[indiceOffset++] = start; ibuf[indiceOffset++] = start + 1; ibuf[indiceOffset++] = start + 4; ibuf[indiceOffset++] = start + 1; ibuf[indiceOffset++] = start + 5; ibuf[indiceOffset++] = start + 4; } } // Restore. if (needRecalculation) { frame._capInsets = oldInsets; frame.uvSliced = oldUvSliced; } }, updateWorldVerts(sprite: cc.Sprite): void { const node = sprite.node; const data = sprite._renderData._data; const matrix = (node as any)._worldMatrix; const a = matrix.m00; const b = matrix.m01; const c = matrix.m04; const d = matrix.m05; const tx = matrix.m12; const ty = matrix.m13; for (let row = 0; row < 4; ++row) { const rowD = data[row]; for (let col = 0; col < 4; ++col) { const colD = data[col]; const world = data[4 + row * 4 + col]; world.x = colD.x * a + rowD.y * c + tx; world.y = colD.x * b + rowD.y * d + ty; } } }, }; @ccclass @disallowMultiple @executeInEditMode @menu('ee/Scale9') export class Scale9 extends cc.Component { public update(delta: number): void { const component = this.getComponent(cc.Sprite); const type = component.type; if (type === cc.Sprite.Type.SLICED) { if (component._assembler !== assembler) { // Use custom assembler. this.updateAssembler(); } } } private updateAssembler(): void { const component = this.getComponent(cc.Sprite); assert(component !== null); if (component._assembler !== assembler) { component._assembler = assembler; component._renderData = null; } if (!component._renderData) { component._renderData = component._assembler.createData(component); component._renderData.material = component._material; component.markForUpdateRenderData(true); } } }