初始化

This commit is contained in:
SmallMain
2022-06-25 00:23:03 +08:00
commit ef0589e8e5
2264 changed files with 617829 additions and 0 deletions

View File

@@ -0,0 +1,163 @@
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;

View File

@@ -0,0 +1,47 @@
import { vfmt3D } from './webgl/vertex-format';
import Vec3 from '../value-types/vec3';
let vec3_temps = [];
for (let i = 0; i < 4; i++) {
vec3_temps.push(cc.v3());
}
let Assembler3D = {
floatsPerVert: 6,
uvOffset: 3,
colorOffset: 5,
getBuffer (renderer) {
return renderer._meshBuffer3D;
},
getVfmt () {
return vfmt3D;
},
updateWorldVerts (comp) {
let matrix = comp.node._worldMatrix;
let local = this._local;
let world = this._renderData.vDatas[0];
Vec3.set(vec3_temps[0], local[0], local[1], 0);
Vec3.set(vec3_temps[1], local[2], local[1], 0);
Vec3.set(vec3_temps[2], local[0], local[3], 0);
Vec3.set(vec3_temps[3], local[2], local[3], 0);
let floatsPerVert = this.floatsPerVert;
for (let i = 0; i < 4; i++) {
let vertex = vec3_temps[i];
Vec3.transformMat4(vertex, vertex, matrix);
let dstOffset = floatsPerVert * i;
world[dstOffset] = vertex.x;
world[dstOffset+1] = vertex.y;
world[dstOffset+2] = vertex.z;
}
},
};
cc.Assembler3D = Assembler3D;
export default Assembler3D;

View File

@@ -0,0 +1,86 @@
import Pool from '../utils/pool';
let _assemblerId = 0;
function getAssemblerId (assemblerCtor) {
if (!Object.getOwnPropertyDescriptor(assemblerCtor, '__assemblerId__')) {
assemblerCtor.__assemblerId__ = ++_assemblerId;
}
return assemblerCtor.__assemblerId__;
}
/**
* {
* assembler_ctor_id: []
* }
*/
class AssemblerPool extends Pool {
_pool = {};
put (assembler) {
if (!assembler) return;
if (!this.enabled) {
if (CC_JSB && CC_NATIVERENDERER) {
assembler.destroy && assembler.destroy();
}
return;
}
let id = getAssemblerId(assembler.constructor);
let pool = this._pool;
if (!pool[id]) {
pool[id] = [];
}
if (this.count > this.maxSize) return;
this._clean(assembler);
pool[id].push(assembler);
this.count++;
}
get (assemblerCtor) {
let assembler;
if (this.enabled) {
let pool = this._pool;
let id = getAssemblerId(assemblerCtor);
assembler = pool[id] && pool[id].pop();
}
if (!assembler) {
assembler = new assemblerCtor();
}
else {
this.count--;
}
return assembler;
}
clear () {
if (CC_JSB && CC_NATIVERENDERER) {
let pool = this._pool;
for (let name in pool) {
let assemblers = pool[name];
if (!assemblers) continue;
for (let i = 0; i < assemblers.length; i++) {
assemblers[i].destroy && assemblers[i].destroy();
}
}
}
this._pool = {};
this.count = 0;
}
_clean (assembler) {
if (CC_JSB && CC_NATIVERENDERER) {
assembler.reset();
}
assembler._renderComp = null;
}
}
let pool = new AssemblerPool();
Pool.register('assembler', pool);
export default pool;

View File

@@ -0,0 +1,50 @@
import { vfmtPosUvColor } from './webgl/vertex-format';
import assemblerPool from './assembler-pool';
export default class Assembler {
constructor () {
this._extendNative && this._extendNative();
}
init (renderComp) {
this._renderComp = renderComp;
}
updateRenderData (comp) {
}
fillBuffers (comp, renderer) {
}
getVfmt () {
return vfmtPosUvColor;
}
}
Assembler.register = function (renderCompCtor, assembler) {
renderCompCtor.__assembler__ = assembler;
};
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;
}
};
cc.Assembler = Assembler;

View File

@@ -0,0 +1,94 @@
// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
var Device = function Device(canvasEL) {
var ctx;
try {
ctx = canvasEL.getContext('2d');
} catch (err) {
console.error(err);
return;
}
// statics
this._canvas = canvasEL;
this._ctx = ctx;
this._caps = {}; // capability
this._stats = {
drawcalls: 0,
};
// runtime
this._vx = this._vy = this._vw = this._vh = 0;
this._sx = this._sy = this._sw = this._sh = 0;
};
Device.prototype._restoreTexture = function _restoreTexture (unit) {
};
// ===============================
// Immediate Settings
// ===============================
/**
* @method setViewport
* @param {Number} x
* @param {Number} y
* @param {Number} w
* @param {Number} h
*/
Device.prototype.setViewport = function setViewport (x, y, w, h) {
if (
this._vx !== x ||
this._vy !== y ||
this._vw !== w ||
this._vh !== h
) {
this._vx = x;
this._vy = y;
this._vw = w;
this._vh = h;
}
};
/**
* @method setScissor
* @param {Number} x
* @param {Number} y
* @param {Number} w
* @param {Number} h
*/
Device.prototype.setScissor = function setScissor (x, y, w, h) {
if (
this._sx !== x ||
this._sy !== y ||
this._sw !== w ||
this._sh !== h
) {
this._sx = x;
this._sy = y;
this._sw = w;
this._sh = h;
}
};
Device.prototype.clear = function clear (color) {
var ctx = this._ctx;
ctx.clearRect(this._vx, this._vy, this._vw, this._vh);
if (color && (color[0] !== 0 || color[1] !== 0 || color[2] !== 0)) {
ctx.fillStyle = 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] +')';
ctx.globalAlpha = color[3];
ctx.fillRect(this._vx, this._vy, this._vw, this._vh);
}
};
Device.prototype.resetDrawCalls = function () {
this._stats.drawcalls = 0;
}
Device.prototype.getDrawCalls = function () {
return this._stats.drawcalls;
}
module.exports = Device;

View File

@@ -0,0 +1,41 @@
// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
var Texture2D = function Texture2D(device, options) {
this._device = device;
this._width = 4;
this._height = 4;
this._image = null;
if (options) {
if (options.width !== undefined) {
this._width = options.width;
}
if (options.height !== undefined) {
this._height = options.height;
}
this.updateImage(options);
}
};
Texture2D.prototype.update = function update (options) {
this.updateImage(options);
};
Texture2D.prototype.updateImage = function updateImage (options) {
if (options.images && options.images[0]) {
var image = options.images[0];
if (image && image !== this._image) {
this._image = image;
}
}
};
Texture2D.prototype.destroy = function destroy () {
this._image = null;
};
module.exports = Texture2D;

View File

@@ -0,0 +1,41 @@
/****************************************************************************
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 ForwardRenderer = function () {
}
ForwardRenderer.prototype = {
constructor: ForwardRenderer,
clear () {
},
render () {
}
};
module.exports = ForwardRenderer;

View File

@@ -0,0 +1,34 @@
/****************************************************************************
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 './render-flow';
import './renderers';
import ForwardRenderer from './forward-renderer';
import RenderComponentHandle from './render-component-handle';
export default {
ForwardRenderer,
RenderComponentHandle
};

View File

@@ -0,0 +1,63 @@
/****************************************************************************
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 utils = require('./renderers/utils')
let RenderComponentHandle = function (device, defaultCamera) {
this._device = device;
// let vx = this._device._vx;
// let vy = this._device._vy;
// let vh = this._device._vh;
this._camera = defaultCamera;
this.parentOpacity = 1;
this.parentOpacityDirty = 0;
this.worldMatDirty = 0;
this.walking = false;
};
RenderComponentHandle.prototype = {
constructor: RenderComponentHandle,
reset() {
let ctx = this._device._ctx;
let canvas = this._device._canvas;
var color = cc.Camera.main ? cc.Camera.main.backgroundColor : cc.color();
let rgba = `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a/255})`;
ctx.fillStyle = rgba;
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillRect(0, 0, canvas.width, canvas.height);
this._device._stats.drawcalls = 0;
//reset cache data
utils.context.reset();
},
terminate () {
}
};
module.exports = RenderComponentHandle;

View File

@@ -0,0 +1,46 @@
/****************************************************************************
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 RenderFlow from '../render-flow';
RenderFlow.prototype._draw = function (node, func) {
let batcher = RenderFlow.getBachther();
let ctx = batcher._device._ctx;
let cam = batcher._camera;
ctx.setTransform(cam.a, cam.b, cam.c, cam.d, cam.tx, cam.ty);
ctx.scale(1, -1);
let comp = node._renderComponent;
comp._assembler[func](ctx, comp);
this._next._func(node);
}
RenderFlow.prototype._render = function (node) {
this._draw(node, 'draw');
}
RenderFlow.prototype._postRender = function (node) {
this._draw(node, 'postDraw');
}

View File

@@ -0,0 +1,159 @@
/****************************************************************************
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 Helper = require('../../../../graphics/helper');
const Types = require('../../../../graphics/types');
const js = require('../../../../platform/js');
const LineJoin = Types.LineJoin;
const LineCap = Types.LineCap;
function Impl () {
this.cmds = [];
this.style = {
strokeStyle: 'black',
fillStyle: 'white',
lineCap: 'butt',
lineJoin: 'miter',
miterLimit: 10
};
}
let _proto = Impl.prototype;
js.mixin(_proto, {
moveTo (x, y) {
this.cmds.push(['moveTo', [x, y]]);
},
lineTo (x, y) {
this.cmds.push(['lineTo', [x, y]]);
},
bezierCurveTo (c1x, c1y, c2x, c2y, x, y) {
this.cmds.push(['bezierCurveTo', [c1x, c1y, c2x, c2y, x, y]]);
},
quadraticCurveTo (cx, cy, x, y) {
this.cmds.push(['quadraticCurveTo', [cx, cy, x, y]]);
},
arc (cx, cy, r, startAngle, endAngle, counterclockwise) {
Helper.arc(this, cx, cy, r, startAngle, endAngle, counterclockwise);
},
ellipse (cx, cy, rx, ry) {
Helper.ellipse(this, cx, cy, rx, ry);
},
circle (cx, cy, r) {
Helper.ellipse(this, cx, cy, r, r);
},
rect (x, y, w, h) {
this.moveTo(x, y);
this.lineTo(x, y + h);
this.lineTo(x + w, y + h);
this.lineTo(x + w, y);
this.close();
},
roundRect (x, y, w, h, r) {
Helper.roundRect(this, x, y, w, h, r);
},
clear (comp, clean) {
this.cmds.length = 0;
},
close () {
this.cmds.push(['closePath', []]);
},
stroke () {
this.cmds.push(['stroke', []]);
},
fill () {
this.cmds.push(['fill', []]);
}
});
js.set(_proto, 'strokeColor', function (v) {
var strokeStyle = 'rgba(' + (0 | v.r) + ',' + (0 | v.g) + ',' + (0 | v.b) + ',' + v.a / 255 + ')';
this.cmds.push(['strokeStyle', strokeStyle]);
this.style.strokeStyle = strokeStyle;
});
js.set(_proto, 'fillColor', function (v) {
var fillStyle = 'rgba(' + (0 | v.r) + ',' + (0 | v.g) + ',' + (0 | v.b) + ',' + v.a / 255 + ')';
this.cmds.push(['fillStyle', fillStyle]);
this.style.fillStyle = fillStyle;
});
js.set(_proto, 'lineWidth', function (v) {
this.cmds.push(['lineWidth', v]);
this.style.lineWidth = v;
});
js.set(_proto, 'lineCap', function (v) {
var lineCap = 'butt';
if (v === LineCap.BUTT) {
lineCap = 'butt';
}
else if (v === LineCap.ROUND) {
lineCap = 'round';
}
else if (v === LineCap.SQUARE) {
lineCap = 'square';
}
this.cmds.push(['lineCap', lineCap]);
this.style.lineCap = lineCap;
});
js.set(_proto, 'lineJoin', function (v) {
var lineJoin = 'bevel';
if (v === LineJoin.BEVEL) {
lineJoin = 'bevel';
}
else if (v === LineJoin.ROUND) {
lineJoin = 'round';
}
else if (v === LineJoin.MITER) {
lineJoin = 'miter';
}
this.cmds.push(['lineJoin', lineJoin]);
this.style.lineJoin = lineJoin;
});
js.set(_proto, 'miterLimit', function (v) {
this.cmds.push(['miterLimit', v]);
this.style.miterLimit = v;
});
cc.Graphics._Impl = Impl;
module.exports = Impl;

View File

@@ -0,0 +1,94 @@
/****************************************************************************
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.
****************************************************************************/
import Assembler from '../../../assembler';
import Impl from './impl';
import Graphics from '../../../../graphics/graphics';
export default class CanvasGraphicsAssembler {
init () {}
updateRenderData () {}
draw (ctx, comp) {
let node = comp.node;
// Transform
let matrix = node._worldMatrix;
let matrixm = matrix.m;
let a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
tx = matrixm[12], ty = matrixm[13];
ctx.transform(a, b, c, d, tx, ty);
ctx.save();
// TODO: handle blend function
// opacity
ctx.globalAlpha = node.opacity / 255;
let style = comp._impl.style;
ctx.strokeStyle = style.strokeStyle;
ctx.fillStyle = style.fillStyle;
ctx.lineWidth = style.lineWidth;
ctx.lineJoin = style.lineJoin;
ctx.miterLimit = style.miterLimit;
let endPath = true;
let cmds = comp._impl.cmds;
for (let i = 0, l = cmds.length; i < l; i++) {
let cmd = cmds[i];
let ctxCmd = cmd[0], args = cmd[1];
if (ctxCmd === 'moveTo' && endPath) {
ctx.beginPath();
endPath = false;
}
else if (ctxCmd === 'fill' || ctxCmd === 'stroke' || ctxCmd === 'fillRect') {
endPath = true;
}
if (typeof ctx[ctxCmd] === 'function') {
ctx[ctxCmd].apply(ctx, args);
}
else {
ctx[ctxCmd] = args;
}
}
ctx.restore();
return 1;
}
stroke (comp) {
comp._impl.stroke();
}
fill (comp) {
comp._impl.fill();
}
clear () {}
}
Assembler.register(Graphics, CanvasGraphicsAssembler);

View File

@@ -0,0 +1,34 @@
/****************************************************************************
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 '../../../components/CCSprite';
import '../../../components/CCLabel';
import '../../../components/CCMask';
import '../../../graphics/graphics';
import './sprite';
import './label';
import './graphics';
import './mask';

View File

@@ -0,0 +1,117 @@
/****************************************************************************
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.
****************************************************************************/
import BmfontAssembler from '../../../utils/label/bmfont';
import RenderData from '../render-data';
import utils from '../utils';
export default class CanvasBmfontAssembler extends BmfontAssembler {
init () {
this._renderData = new RenderData();
}
updateColor () {}
appendQuad (comp, texture, rect, rotated, x, y, scale) {
let renderData = this._renderData;
let dataOffset = renderData.dataLength;
renderData.dataLength += 2;
let verts = renderData.vertices;
let rectWidth = rect.width,
rectHeight = rect.height;
let l, b, r, t;
if (!rotated) {
l = rect.x;
r = rect.x + rectWidth;
b = rect.y;
t = rect.y + rectHeight;
verts[dataOffset].u = l;
verts[dataOffset].v = b;
verts[dataOffset+1].u = r;
verts[dataOffset+1].v = t;
} else {
l = rect.x;
r = rect.x + rectHeight;
b = rect.y;
t = rect.y + rectWidth;
verts[dataOffset].u = l;
verts[dataOffset].v = t;
verts[dataOffset+1].u = l;
verts[dataOffset+1].v = b;
}
verts[dataOffset].x = x;
verts[dataOffset].y = y - rectHeight * scale;
verts[dataOffset+1].x = x + rectWidth * scale;
verts[dataOffset+1].y = y;
}
draw (ctx, comp) {
let node = comp.node;
// Transform
let matrix = node._worldMatrix;
let matrixm = matrix.m;
let a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
tx = matrixm[12], ty = matrixm[13];
ctx.transform(a, b, c, d, tx, ty);
ctx.scale(1, -1);
// TODO: handle blend function
// opacity
utils.context.setGlobalAlpha(ctx, node.opacity / 255);
let tex = comp._frame._texture,
verts = this._renderData.vertices;
let image = utils.getColorizedImage(tex, node._color);
for (let i = 0, l = verts.length; i < l; i+=2) {
let x = verts[i].x;
let y = verts[i].y;
let w = verts[i+1].x - x;
let h = verts[i+1].y - y;
y = - y - h;
let sx = verts[i].u;
let sy = verts[i].v;
let sw = verts[i+1].u - sx;
let sh = verts[i+1].v - sy;
ctx.drawImage(image,
sx, sy, sw, sh,
x, y, w, h);
}
return 1;
}
}

View File

@@ -0,0 +1,76 @@
/****************************************************************************
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.
****************************************************************************/
import Assembler from '../../../assembler';
import Label from '../../../../components/CCLabel';
import TTF from './ttf';
import Bmfont from './bmfont';
let canvasPool = {
pool: [],
get () {
let data = this.pool.pop();
if (!data) {
let canvas = document.createElement("canvas");
let context = canvas.getContext("2d");
data = {
canvas: canvas,
context: context
}
// default text info
context.textBaseline = 'alphabetic';
}
return data;
},
put (canvas) {
if (this.pool.length >= 32) {
return;
}
this.pool.push(canvas);
}
};
Label._canvasPool = canvasPool;
Assembler.register(Label, {
getConstructor(label) {
let ctor = TTF;
if (label.font instanceof cc.BitmapFont) {
ctor = Bmfont;
} else if (label.cacheMode === Label.CacheMode.CHAR) {
cc.warn('sorry, canvas mode does not support CHAR mode currently!');
}
return ctor;
},
TTF,
Bmfont
});

View File

@@ -0,0 +1,90 @@
/****************************************************************************
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.
****************************************************************************/
import TTFAssembler from '../../../utils/label/ttf';
import RenderData from '../render-data';
import utils from '../utils';
export default class CanvasTTFAssembler extends TTFAssembler {
init () {
this._renderData = new RenderData();
this._renderData.dataLength = 2;
}
updateColor () {
}
updateVerts (comp) {
let renderData = this._renderData;
let node = comp.node,
width = node.width,
height = node.height,
appx = node.anchorX * width,
appy = node.anchorY * height;
let verts = renderData.vertices;
verts[0].x = -appx;
verts[0].y = -appy;
verts[1].x = width - appx;
verts[1].y = height - appy;
}
_updateTexture (comp) {
TTFAssembler.prototype._updateTexture.call(this, comp);
let texture = comp._frame._texture;
utils.dropColorizedImage(texture, comp.node.color);
}
draw (ctx, comp) {
let node = comp.node;
// Transform
let matrix = node._worldMatrix;
let matrixm = matrix.m;
let a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
tx = matrixm[12], ty = matrixm[13];
ctx.transform(a, b, c, d, tx, ty);
ctx.scale(1, -1);
// TODO: handle blend function
// opacity
utils.context.setGlobalAlpha(ctx, node.opacity / 255);
let tex = comp._frame._texture,
verts = this._renderData.vertices;
let image = tex.getHtmlElementObj();
let x = verts[0].x;
let y = verts[0].y;
let w = verts[1].x - x;
let h = verts[1].y - y;
y = - y - h;
ctx.drawImage(image, x, y, w, h);
return 1;
}
}

View File

@@ -0,0 +1,45 @@
/****************************************************************************
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 Mask = require('../../../components/CCMask');
const graphicsHandler = require('./graphics');
import Assembler from '../../assembler';
export default class CanvasMaskAssembler extends Assembler {
draw (ctx, mask) {
ctx.save();
// draw stencil
mask._graphics._assembler.draw(ctx, mask._graphics);
ctx.clip();
}
postDraw (ctx, mask) {
ctx.restore();
}
}
Assembler.register(Mask, CanvasMaskAssembler);

View File

@@ -0,0 +1,22 @@
export default class RenderData {
constructor () {
this.vertices = [];
}
get dataLength () {
return this.vertices.length;
}
set dataLength (v) {
let old = this.vertices.length;
this.vertices.length = v;
for (let i = old; i < v; i++) {
this.vertices[i] = {
x: 0.0,
y: 0.0,
u: 0.0,
v: 0.0,
};
}
}
}

View File

@@ -0,0 +1,28 @@
import Asembler from '../../../assembler';
import { Type } from '../../../../components/CCSprite';
import Simple from "./simple";
import Sliced from "./sliced";
import Tiled from "./tiled";
let ctor = {
getConstructor(sprite) {
let ctor = Simple;
switch (sprite.type) {
case Type.SLICED:
ctor = Sliced;
break;
case Type.TILED:
ctor = Tiled;
break;
}
return ctor;
},
Simple,
Sliced,
Tiled
};
Asembler.register(cc.Sprite, ctor);

View File

@@ -0,0 +1,155 @@
/****************************************************************************
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.
****************************************************************************/
import Assembler from '../../../assembler';
import RenderData from '../render-data';
const utils = require('../utils');
export default class CanvasSimpleSprite extends Assembler {
init () {
this._renderData = new RenderData();
this._renderData.dataLength = 2;
}
updateRenderData (sprite) {
if (sprite._vertsDirty) {
this.updateUVs(sprite);
this.updateVerts(sprite);
sprite._vertsDirty = false;
}
}
updateUVs (sprite) {
let frame = sprite.spriteFrame;
let renderData = this._renderData;
let verts = renderData.vertices;
let rect = frame._rect;
if (frame._rotated) {
let l = rect.x;
let r = rect.width;
let b = rect.y;
let t = rect.height;
verts[0].u = l;
verts[0].v = b;
verts[1].u = t;
verts[1].v = r;
}
else {
let l = rect.x;
let r = rect.width;
let b = rect.y;
let t = rect.height;
verts[0].u = l;
verts[0].v = b;
verts[1].u = r;
verts[1].v = t;
}
}
updateVerts (sprite) {
let renderData = this._renderData,
node = sprite.node,
verts = renderData.vertices,
frame = sprite.spriteFrame,
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;
t = ch;
}
else {
let 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 trimBottom = offset.y + (oh - rh) / 2;
l = trimLeft * scaleX - appx;
b = trimBottom * scaleY - appy;
r = cw;
t = ch;
}
if (frame._rotated) {
verts[0].y = l;
verts[0].x = b;
verts[1].y = r;
verts[1].x = t;
} else {
verts[0].x = l;
verts[0].y = b;
verts[1].x = r;
verts[1].y = t;
}
renderData.vertDirty = false;
}
draw (ctx, comp) {
let node = comp.node;
let frame = comp._spriteFrame;
// Transform
let matrix = node._worldMatrix;
let matrixm = matrix.m;
let a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
tx = matrixm[12], ty = matrixm[13];
ctx.transform(a, b, c, d, tx, ty);
ctx.scale(1, -1);
if (frame._rotated) {
ctx.rotate(- Math.PI / 2);
}
// TODO: handle blend function
// opacity
utils.context.setGlobalAlpha(ctx, node.opacity / 255);
let tex = frame._texture,
verts = this._renderData.vertices;
let image = utils.getColorizedImage(tex, node._color);
let x = verts[0].x;
let y = verts[0].y;
let w = verts[1].x;
let h = verts[1].y;
y = - y - h;
let sx = verts[0].u;
let sy = verts[0].v;
let sw = verts[1].u;
let sh = verts[1].v;
ctx.drawImage(image,
sx, sy, sw, sh,
x, y, w, h);
return 1;
}
}

View File

@@ -0,0 +1,175 @@
/****************************************************************************
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.
****************************************************************************/
import Assembler from '../../../assembler';
import RenderData from '../render-data';
import CanvasSimpleSprite from './simple';
const utils = require('../utils');
export default class CanvasSlicedSprite extends CanvasSimpleSprite {
init () {
this._renderData = new RenderData();
this._renderData.dataLength = 4;
}
updateUVs (sprite) {
let frame = sprite.spriteFrame;
let renderData = this._renderData;
let rect = frame._rect;
// caculate texture coordinate
let leftWidth = frame.insetLeft;
let rightWidth = frame.insetRight;
let centerWidth = rect.width - leftWidth - rightWidth;
let topHeight = frame.insetTop;
let bottomHeight = frame.insetBottom;
let centerHeight = rect.height - topHeight - bottomHeight;
// uv computation should take spritesheet into account.
let verts = renderData.vertices;
if (frame._rotated) {
verts[0].u = rect.x;
verts[1].u = bottomHeight + rect.x;
verts[2].u = bottomHeight + centerHeight + rect.x;
verts[3].u = rect.x + rect.height;
verts[3].v = rect.y;
verts[2].v = leftWidth + rect.y;
verts[1].v = leftWidth + centerWidth + rect.y;
verts[0].v = rect.y + rect.width;
}
else {
verts[0].u = rect.x;
verts[1].u = leftWidth + rect.x;
verts[2].u = leftWidth + centerWidth + rect.x;
verts[3].u = rect.x + rect.width;
verts[3].v = rect.y;
verts[2].v = topHeight + rect.y;
verts[1].v = topHeight + centerHeight + rect.y;
verts[0].v = rect.y + rect.height;
}
}
updateVerts (sprite) {
let renderData = this._renderData,
verts = renderData.vertices,
node = sprite.node,
width = node.width, height = node.height,
appx = node.anchorX * width, appy = node.anchorY * height;
let frame = sprite.spriteFrame;
let leftWidth = frame.insetLeft;
let rightWidth = frame.insetRight;
let topHeight = frame.insetTop;
let 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;
if (frame._rotated) {
verts[0].y = -appx;
verts[0].x = -appy;
verts[1].y = rightWidth * xScale - appx;
verts[1].x = bottomHeight * yScale - appy;
verts[2].y = verts[1].y + sizableWidth;
verts[2].x = verts[1].x + sizableHeight;
verts[3].y = width - appx;
verts[3].x = height - appy;
} else {
verts[0].x = -appx;
verts[0].y = -appy;
verts[1].x = leftWidth * xScale - appx;
verts[1].y = bottomHeight * yScale - appy;
verts[2].x = verts[1].x + sizableWidth;
verts[2].y = verts[1].y + sizableHeight;
verts[3].x = width - appx;
verts[3].y = height - appy;
}
sprite._vertsDirty = false;
}
draw (ctx, comp) {
let node = comp.node;
let frame = comp._spriteFrame;
// Transform
let matrix = node._worldMatrix;
let matrixm = matrix.m;
let a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
tx = matrixm[12], ty = matrixm[13];
ctx.transform(a, b, c, d, tx, ty);
ctx.scale(1, -1);
if (frame._rotated) {
ctx.rotate(- Math.PI / 2);
}
// TODO: handle blend function
// opacity
utils.context.setGlobalAlpha(ctx, node.opacity / 255);
let tex = frame._texture,
verts = this._renderData.vertices;
let image = utils.getColorizedImage(tex, node._color);
let drawCall = 0;
let off, ld, rd, td, bd,
x, y, w, h,
sx, sy, sw, sh;
for (let r = 0; r < 3; ++r) {
bd = verts[r];
td = verts[r+1];
for (let c = 0; c < 3; ++c) {
ld = verts[c];
rd = verts[c+1];
x = ld.x;
y = bd.y;
w = rd.x - x;
h = td.y - y;
y = - y - h;
sx = ld.u;
// invert texture because texture uv is in UI coordinates (origin at top left)
sy = td.v;
sw = rd.u - sx;
sh = bd.v - sy;
if (sw > 0 && sh > 0 && w > 0 && h > 0) {
ctx.drawImage(image,
sx, sy, sw, sh,
x, y, w, h);
drawCall++;
}
}
}
return drawCall;
}
}

View File

@@ -0,0 +1,67 @@
/****************************************************************************
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.
****************************************************************************/
import Assembler from '../../../assembler';
const utils = require('../utils');
export default class CanvasTiledSprite extends Assembler {
draw (ctx, sprite) {
let node = sprite.node;
// Transform
let matrix = node._worldMatrix;
let matrixm = matrix.m;
let a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
tx = matrixm[12], ty = matrixm[13];
ctx.transform(a, b, c, d, tx, ty);
ctx.scale(1, -1);
// TODO: handle blend function
// opacity
utils.context.setGlobalAlpha(ctx, node.opacity / 255);
let frame = sprite.spriteFrame;
let rect = frame._rect;
let tex = frame._texture;
let sx = rect.x;
let sy = rect.y;
let sw = frame._rotated ? rect.height : rect.width;
let sh = frame._rotated ? rect.width : rect.height;
let image = utils.getFrameCache(tex, node._color, sx, sy, sw, sh);
let w = node.width,
h = node.height,
x = -node.anchorX * w,
y = -node.anchorY * h;
y = - y - h;
ctx.translate(x, y);
ctx.fillStyle = ctx.createPattern(image, 'repeat');
ctx.fillRect(0, 0, w, h);
return 1;
}
}

View File

@@ -0,0 +1,183 @@
/****************************************************************************
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 WHITE = (255<<16) + (255<<8) + 255;
const MAX_CANVAS_COUNT = 32;
function colorizedFrame (canvas, texture, color, sx, sy, sw, sh) {
let image = texture._image;
let ctx = canvas.getContext("2d");
canvas.width = sw;
canvas.height = sh;
// Draw color
ctx.globalCompositeOperation = 'source-over';
ctx.fillStyle = 'rgb(' + color.r + ',' + color.g + ',' + color.b + ')';
ctx.fillRect(0, 0, sw, sh);
// Multiply color with texture
ctx.globalCompositeOperation = 'multiply';
ctx.drawImage(image, sx, sy, sw, sh, 0, 0, sw, sh);
// Clip out transparent pixels
ctx.globalCompositeOperation = "destination-atop";
ctx.drawImage(image, sx, sy, sw, sh, 0, 0, sw, sh);
return canvas;
}
let canvasMgr = {
canvasMap: {},
canvasUsed: {},
canvasPool: [],
checking: false,
check () {
let exist = false;
for (let key in this.canvasUsed) {
exist = true;
if (!this.canvasUsed[key]) {
let canvas = this.canvasMap[key];
canvas.width = 0;
canvas.height = 0;
if (this.canvasPool.length < 32) {
this.canvasPool.push(canvas);
}
delete this.canvasMap[key];
delete this.canvasUsed[key];
}
else {
this.canvasUsed[key] = false;
}
}
if (!exist) {
cc.director.off(cc.Director.EVENT_AFTER_DRAW, this.check, this);
this.checking = false;
}
},
startCheck () {
cc.director.on(cc.Director.EVENT_AFTER_DRAW, this.check, this);
this.checking = true;
},
getCanvas (key) {
this.canvasUsed[key] = true;
return this.canvasMap[key];
},
cacheCanvas (canvas, key) {
this.canvasMap[key] = canvas;
this.canvasUsed[key] = true;
if (!this.checking) {
this.startCheck();
}
},
dropImage (key) {
if (this.canvasMap[key]) {
delete this.canvasMap[key];
}
}
};
module.exports = {
getColorizedImage (texture, color) {
if (!texture) return null;
if (texture.width === 0 || texture.height === 0) return texture._image;
// original image
let cval = color._val & 0x00ffffff;
if (cval === WHITE) {
return texture._image;
}
// get from cache
let key = texture.nativeUrl + cval;
let cache = canvasMgr.getCanvas(key);
if (!cache) {
cache = canvasMgr.canvasPool.pop() || document.createElement("canvas");
colorizedFrame(cache, texture, color, 0, 0, texture.width, texture.height);
canvasMgr.cacheCanvas(cache, key);
}
return cache;
},
getFrameCache (texture, color, sx, sy, sw, sh) {
if (!texture || !texture.nativeUrl || sx < 0 || sy < 0 || sw <= 0 || sh <= 0) {
return null;
}
let key = texture.nativeUrl;
let generate = false;
let cval = color._val & 0x00ffffff;
if (cval !== WHITE) {
key += cval;
generate = true;
}
if (sx !== 0 || sy !== 0 && sw !== texture.width && sh !== texture.height) {
key += '_' + sx + '_' + sy + '_' + sw + '_' + sh;
generate = true;
}
if (!generate) {
return texture._image;
}
// get from cache
let cache = canvasMgr.getCanvas(key);
if (!cache) {
cache = canvasMgr.canvasPool.pop() || document.createElement("canvas");
colorizedFrame(cache, texture, color, sx, sy, sw, sh);
canvasMgr.cacheCanvas(cache, key);
}
return cache;
},
dropColorizedImage (texture, color) {
let key = texture.nativeUrl + (color._val & 0x00ffffff);
canvasMgr.dropImage(key);
}
};
// cache context data of device.
let _globalAlpha = -1;
let context = {
setGlobalAlpha (ctx, alpha) {
if (_globalAlpha === alpha) {
return
}
_globalAlpha = alpha;
ctx.globalAlpha = _globalAlpha;
},
reset () {
_globalAlpha = -1;
}
}
module.exports.context = context;

View File

@@ -0,0 +1,188 @@
/****************************************************************************
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 gfx from '../../renderer/gfx';
import InputAssembler from '../../renderer/core/input-assembler';
import Pass from '../../renderer/core/pass';
// const RenderFlow = require('./render-flow');
function _initBuiltins(device) {
let defaultTexture = new gfx.Texture2D(device, {
images: [],
width: 128,
height: 128,
wrapS: gfx.WRAP_REPEAT,
wrapT: gfx.WRAP_REPEAT,
format: gfx.TEXTURE_FMT_RGB8,
genMipmaps: false,
});
return {
defaultTexture: defaultTexture,
programTemplates: [],
programChunks: {},
};
}
/**
* @module cc
*/
/**
* !#en The renderer object which provide access to render system APIs,
* detailed APIs will be available progressively.
* !#zh 提供基础渲染接口的渲染器对象,渲染层的基础接口将逐步开放给用户
* @class renderer
* @static
*/
export default cc.renderer = {
Texture2D: null,
InputAssembler: InputAssembler,
Pass: Pass,
/**
* !#en The render engine is available only after cc.game.EVENT_ENGINE_INITED event.<br/>
* Normally it will be inited as the webgl render engine, but in wechat open context domain,
* it will be inited as the canvas render engine. Canvas render engine is no longer available for other use case since v2.0.
* !#zh 基础渲染引擎对象只在 cc.game.EVENT_ENGINE_INITED 事件触发后才可获取。<br/>
* 大多数情况下,它都会是 WebGL 渲染引擎实例,但是在微信开放数据域当中,它会是 Canvas 渲染引擎实例。请注意,从 2.0 开始,我们在其他平台和环境下都废弃了 Canvas 渲染器。
* @property renderEngine
* @deprecated
* @type {Object}
*/
renderEngine: null,
/*
* !#en The canvas object which provides the rendering context
* !#zh 用于渲染的 Canvas 对象
* @property canvas
* @type {HTMLCanvasElement}
*/
canvas: null,
/*
* !#en The device object which provides device related rendering functionality, it divers for different render engine type.
* !#zh 提供设备渲染能力的对象,它对于不同的渲染环境功能也不相同。
* @property device
* @type {renderer.Device}
*/
device: null,
scene: null,
/**
* !#en The total draw call count in last rendered frame.
* !#zh 上一次渲染帧所提交的渲染批次总数。
* @property drawCalls
* @type {Number}
*/
drawCalls: 0,
// Render component handler
_handle: null,
_cameraNode: null,
_camera: null,
_forward: null,
_flow: null,
initWebGL (canvas, opts) {
require('./webgl/assemblers');
const ModelBatcher = require('./webgl/model-batcher');
this.Texture2D = gfx.Texture2D;
this.canvas = canvas;
this._flow = cc.RenderFlow;
if (CC_JSB && CC_NATIVERENDERER) {
// native codes will create an instance of Device, so just use the global instance.
this.device = gfx.Device.getInstance();
this.scene = new renderer.Scene();
let builtins = _initBuiltins(this.device);
this._forward = new renderer.ForwardRenderer(this.device, builtins);
let nativeFlow = new renderer.RenderFlow(this.device, this.scene, this._forward);
this._flow.init(nativeFlow);
}
else {
let Scene = require('../../renderer/scene/scene');
let ForwardRenderer = require('../../renderer/renderers/forward-renderer');
this.device = new gfx.Device(canvas, opts);
this.scene = new Scene();
let builtins = _initBuiltins(this.device);
this._forward = new ForwardRenderer(this.device, builtins);
this._handle = new ModelBatcher(this.device, this.scene);
this._flow.init(this._handle, this._forward);
}
},
initCanvas (canvas) {
const canvasRenderer = require('./canvas');
const Texture2D = require('./canvas/Texture2D');
const Device = require('./canvas/Device');
// It's actually running with original render engine
this.Device = Device;
this.Texture2D = Texture2D;
this.canvas = canvas;
this.device = new Device(canvas);
this._camera = {
a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0
};
this._handle = new canvasRenderer.RenderComponentHandle(this.device, this._camera);
this._forward = new canvasRenderer.ForwardRenderer();
this._flow = cc.RenderFlow;
this._flow.init(this._handle, this._forward);
},
updateCameraViewport () {
// TODO: remove HACK
if (!CC_EDITOR && cc.director) {
let ecScene = cc.director.getScene();
if (ecScene) ecScene.setScale(1, 1, 1);
}
if (cc.game.renderType === cc.game.RENDER_TYPE_CANVAS) {
let vp = cc.view.getViewportRect();
this.device.setViewport(vp.x, vp.y, vp.width, vp.height);
this._camera.a = cc.view.getScaleX();
this._camera.d = cc.view.getScaleY();
this._camera.tx = vp.x;
this._camera.ty = vp.y + vp.height;
}
},
render (ecScene, dt) {
this.device.resetDrawCalls();
if (ecScene) {
// walk entity component scene to generate models
this._flow.render(ecScene, dt);
this.drawCalls = this.device.getDrawCalls();
}
},
clear () {
this._handle.reset();
this._forward.clear();
}
};

View File

@@ -0,0 +1,287 @@
let FlagOfset = 0;
const DONOTHING = 1 << FlagOfset++;
const BREAK_FLOW = 1 << FlagOfset++;
const LOCAL_TRANSFORM = 1 << FlagOfset++;
const WORLD_TRANSFORM = 1 << FlagOfset++;
const TRANSFORM = LOCAL_TRANSFORM | WORLD_TRANSFORM;
const UPDATE_RENDER_DATA = 1 << FlagOfset++;
const OPACITY = 1 << FlagOfset++;
const COLOR = 1 << FlagOfset++;
const OPACITY_COLOR = OPACITY | COLOR;
const RENDER = 1 << FlagOfset++;
const CHILDREN = 1 << FlagOfset++;
const POST_RENDER = 1 << FlagOfset++;
const FINAL = 1 << FlagOfset++;
let _batcher, _forward;
let _cullingMask = 0;
function RenderFlow () {
this._func = init;
this._next = null;
}
let _proto = RenderFlow.prototype;
_proto._doNothing = function () {
};
_proto._localTransform = function (node) {
node._updateLocalMatrix();
node._renderFlag &= ~LOCAL_TRANSFORM;
this._next._func(node);
};
_proto._worldTransform = function (node) {
_batcher.worldMatDirty ++;
let t = node._matrix;
let trs = node._trs;
let tm = t.m;
tm[12] = trs[0];
tm[13] = trs[1];
tm[14] = trs[2];
node._mulMat(node._worldMatrix, node._parent._worldMatrix, t);
node._renderFlag &= ~WORLD_TRANSFORM;
this._next._func(node);
_batcher.worldMatDirty --;
};
_proto._updateRenderData = function (node) {
let comp = node._renderComponent;
comp._assembler.updateRenderData(comp);
node._renderFlag &= ~UPDATE_RENDER_DATA;
this._next._func(node);
};
_proto._opacity = function (node) {
_batcher.parentOpacityDirty++;
this._next._func(node);
node._renderFlag &= ~OPACITY;
_batcher.parentOpacityDirty--;
};
_proto._color = function (node) {
let comp = node._renderComponent;
if (comp) {
comp._updateColor();
}
node._renderFlag &= ~COLOR;
this._next._func(node);
};
_proto._render = function (node) {
let comp = node._renderComponent;
comp._checkBacth(_batcher, node._cullingMask);
comp._assembler.fillBuffers(comp, _batcher);
this._next._func(node);
};
_proto._children = function (node) {
let cullingMask = _cullingMask;
let batcher = _batcher;
let parentOpacity = batcher.parentOpacity;
let opacity = (batcher.parentOpacity *= (node._opacity / 255));
let worldTransformFlag = batcher.worldMatDirty ? WORLD_TRANSFORM : 0;
let worldOpacityFlag = batcher.parentOpacityDirty ? OPACITY_COLOR : 0;
let worldDirtyFlag = worldTransformFlag | worldOpacityFlag;
let children = node._children;
for (let i = 0, l = children.length; i < l; i++) {
let c = children[i];
// Advance the modification of the flag to avoid node attribute modification is invalid when opacity === 0.
c._renderFlag |= worldDirtyFlag;
if (!c._activeInHierarchy || c._opacity === 0) continue;
_cullingMask = c._cullingMask = c.groupIndex === 0 ? cullingMask : 1 << c.groupIndex;
// TODO: Maybe has better way to implement cascade opacity
let colorVal = c._color._val;
c._color._fastSetA(c._opacity * opacity);
flows[c._renderFlag]._func(c);
c._color._val = colorVal;
}
batcher.parentOpacity = parentOpacity;
this._next._func(node);
};
_proto._postRender = function (node) {
let comp = node._renderComponent;
comp._checkBacth(_batcher, node._cullingMask);
comp._assembler.postFillBuffers(comp, _batcher);
this._next._func(node);
};
const EMPTY_FLOW = new RenderFlow();
EMPTY_FLOW._func = EMPTY_FLOW._doNothing;
EMPTY_FLOW._next = EMPTY_FLOW;
let flows = {};
function createFlow (flag, next) {
if (flag === DONOTHING || flag === BREAK_FLOW) {
return EMPTY_FLOW
}
let flow = new RenderFlow();
flow._next = next || EMPTY_FLOW;
switch (flag) {
case LOCAL_TRANSFORM:
flow._func = flow._localTransform;
break;
case WORLD_TRANSFORM:
flow._func = flow._worldTransform;
break;
case UPDATE_RENDER_DATA:
flow._func = flow._updateRenderData;
break;
case OPACITY:
flow._func = flow._opacity;
break;
case COLOR:
flow._func = flow._color;
break;
case RENDER:
flow._func = flow._render;
break;
case CHILDREN:
flow._func = flow._children;
break;
case POST_RENDER:
flow._func = flow._postRender;
break;
}
return flow;
}
function getFlow (flag) {
let flow = null;
let tFlag = FINAL;
while (tFlag > 0) {
if (tFlag & flag)
flow = createFlow(tFlag, flow);
tFlag = tFlag >> 1;
}
return flow;
}
//
function init (node) {
let flag = node._renderFlag;
let r = flows[flag] = getFlow(flag);
r._func(node);
}
RenderFlow.flows = flows;
RenderFlow.createFlow = createFlow;
// validate whether render component is ready to be rendered.
let _validateList = [];
RenderFlow.registerValidate = function (renderComp) {
if (renderComp._inValidateList) return;
_validateList.push(renderComp);
renderComp._inValidateList = true;
};
RenderFlow.validateRenderers = function () {
for (let i = 0, l = _validateList.length; i < l; i++) {
let renderComp = _validateList[i];
if (!renderComp.isValid) continue;
if (!renderComp.enabledInHierarchy) {
renderComp.disableRender();
}
else {
renderComp._validateRender();
}
renderComp._inValidateList = false;
}
_validateList.length = 0;
};
RenderFlow.visitRootNode = function (rootNode) {
RenderFlow.validateRenderers();
let preCullingMask = _cullingMask;
_cullingMask = rootNode._cullingMask;
if (rootNode._renderFlag & WORLD_TRANSFORM) {
_batcher.worldMatDirty ++;
rootNode._calculWorldMatrix();
rootNode._renderFlag &= ~WORLD_TRANSFORM;
flows[rootNode._renderFlag]._func(rootNode);
_batcher.worldMatDirty --;
}
else {
flows[rootNode._renderFlag]._func(rootNode);
}
_cullingMask = preCullingMask;
};
RenderFlow.render = function (rootNode, dt) {
_batcher.reset();
_batcher.walking = true;
RenderFlow.visitRootNode(rootNode);
_batcher.terminate();
_batcher.walking = false;
_forward.render(_batcher._renderScene, dt);
};
RenderFlow.renderCamera = function (camera, rootNode) {
_batcher.reset();
_batcher.walking = true;
RenderFlow.visitRootNode(rootNode);
_batcher.terminate();
_batcher.walking = false;
_forward.renderCamera(camera, _batcher._renderScene);
};
RenderFlow.init = function (batcher, forwardRenderer) {
_batcher = batcher;
_forward = forwardRenderer;
flows[0] = EMPTY_FLOW;
for (let i = 1; i < FINAL; i++) {
flows[i] = new RenderFlow();
}
};
RenderFlow.getBachther = function () {
return _batcher;
};
RenderFlow.FLAG_DONOTHING = DONOTHING;
RenderFlow.FLAG_BREAK_FLOW = BREAK_FLOW;
RenderFlow.FLAG_LOCAL_TRANSFORM = LOCAL_TRANSFORM;
RenderFlow.FLAG_WORLD_TRANSFORM = WORLD_TRANSFORM;
RenderFlow.FLAG_TRANSFORM = TRANSFORM;
RenderFlow.FLAG_UPDATE_RENDER_DATA = UPDATE_RENDER_DATA;
RenderFlow.FLAG_OPACITY = OPACITY;
RenderFlow.FLAG_COLOR = COLOR;
RenderFlow.FLAG_OPACITY_COLOR = OPACITY_COLOR;
RenderFlow.FLAG_RENDER = RENDER;
RenderFlow.FLAG_CHILDREN = CHILDREN;
RenderFlow.FLAG_POST_RENDER = POST_RENDER;
RenderFlow.FLAG_FINAL = FINAL;
module.exports = cc.RenderFlow = RenderFlow;

View File

@@ -0,0 +1,140 @@
const RenderTexture = require('../../../assets/CCRenderTexture');
const space = 2;
function Atlas (width, height) {
let texture = new RenderTexture();
texture.initWithSize(width, height);
texture.update();
this._texture = texture;
this._x = space;
this._y = space;
this._nexty = space;
this._width = width;
this._height = height;
this._innerTextureInfos = {};
this._innerSpriteFrames = [];
this._count = 0;
}
Atlas.DEFAULT_HASH = (new RenderTexture())._getHash();
cc.js.mixin(Atlas.prototype, {
insertSpriteFrame (spriteFrame) {
let rect = spriteFrame._rect,
texture = spriteFrame._texture,
info = this._innerTextureInfos[texture._id];
let sx = rect.x, sy = rect.y;
if (info) {
sx += info.x;
sy += info.y;
}
else {
let width = texture.width, height = texture.height;
if ((this._x + width + space) > this._width) {
this._x = space;
this._y = this._nexty;
}
if ((this._y + height + space) > this._nexty) {
this._nexty = this._y + height + space;
}
if (this._nexty > this._height) {
return null;
}
// texture bleeding
if (cc.dynamicAtlasManager.textureBleeding) {
// Smaller frame is more likely to be affected by linear filter
if (width <= 8 || height <= 8) {
this._texture.drawTextureAt(texture, this._x-1, this._y-1);
this._texture.drawTextureAt(texture, this._x-1, this._y+1);
this._texture.drawTextureAt(texture, this._x+1, this._y-1);
this._texture.drawTextureAt(texture, this._x+1, this._y+1);
}
this._texture.drawTextureAt(texture, this._x-1, this._y);
this._texture.drawTextureAt(texture, this._x+1, this._y);
this._texture.drawTextureAt(texture, this._x, this._y-1);
this._texture.drawTextureAt(texture, this._x, this._y+1);
}
this._texture.drawTextureAt(texture, this._x, this._y);
this._innerTextureInfos[texture._id] = {
x: this._x,
y: this._y,
texture: texture
};
this._count++;
sx += this._x;
sy += this._y;
this._x += width + space;
this._dirty = true;
}
let frame = {
x: sx,
y: sy,
texture: this._texture
}
this._innerSpriteFrames.push(spriteFrame);
return frame;
},
update () {
if (!this._dirty) return;
this._texture.update();
this._dirty = false;
},
deleteInnerTexture (texture) {
if (texture && this._innerTextureInfos[texture._id]) {
delete this._innerTextureInfos[texture._id];
this._count--;
}
},
isEmpty () {
return this._count <= 0;
},
reset () {
this._x = space;
this._y = space;
this._nexty = space;
let frames = this._innerSpriteFrames;
for (let i = 0, l = frames.length; i < l; i++) {
let frame = frames[i];
if (!frame.isValid) {
continue;
}
frame._resetDynamicAtlasFrame();
}
this._innerSpriteFrames.length = 0;
this._innerTextureInfos = {};
},
destroy () {
this.reset();
this._texture.destroy();
}
});
module.exports = Atlas;

View File

@@ -0,0 +1,267 @@
const Atlas = require('./atlas');
let _atlases = [];
let _atlasIndex = -1;
let _maxAtlasCount = 5;
let _textureSize = 2048;
let _maxFrameSize = 512;
let _textureBleeding = true;
let _debugNode = null;
function newAtlas () {
let atlas = _atlases[++_atlasIndex]
if (!atlas) {
atlas = new Atlas(_textureSize, _textureSize);
_atlases.push(atlas);
}
return atlas;
}
function beforeSceneLoad () {
dynamicAtlasManager.reset();
}
let _enabled = false;
/**
* !#en Manage Dynamic Atlas Manager. Dynamic Atlas Manager is used for merging textures at runtime, see [Dynamic Atlas](https://docs.cocos.com/creator/manual/en/advanced-topics/dynamic-atlas.html) for details.
* !#zh 管理动态图集。动态图集用于在运行时对贴图进行合并,详见 [动态合图](https://docs.cocos.com/creator/manual/zh/advanced-topics/dynamic-atlas.html)。
* @class DynamicAtlasManager
*/
let dynamicAtlasManager = {
Atlas: Atlas,
/**
* !#en Enable or disable the dynamic atlas, see [Dynamic Atlas](https://docs.cocos.com/creator/manual/en/advanced-topics/dynamic-atlas.html) for details.
* !#zh 开启或者关闭动态图集,详见 [动态合图](https://docs.cocos.com/creator/manual/zh/advanced-topics/dynamic-atlas.html)。
* @property enabled
* @type {Boolean}
*/
get enabled () {
return _enabled;
},
set enabled (value) {
if (_enabled === value) return;
if (value) {
this.reset();
cc.director.on(cc.Director.EVENT_BEFORE_SCENE_LAUNCH, beforeSceneLoad);
}
else {
cc.director.off(cc.Director.EVENT_BEFORE_SCENE_LAUNCH, beforeSceneLoad);
}
_enabled = value;
},
/**
* !#en The maximum number of atlas that can be created.
* !#zh 可以创建的最大图集数量。
* @property maxAtlasCount
* @type {Number}
*/
get maxAtlasCount () {
return _maxAtlasCount;
},
set maxAtlasCount (value) {
_maxAtlasCount = value;
},
/**
* !#en Get the current created atlas count.
* !#zh 获取当前已经创建的图集数量。
* @property atlasCount
* @type {Number}
*/
get atlasCount () {
return _atlases.length;
},
/**
* !#en Is enable textureBleeding.
* !#zh 是否开启 textureBleeding
* @property textureBleeding
* @type {Boolean}
*/
get textureBleeding () {
return _textureBleeding;
},
set textureBleeding (enable) {
_textureBleeding = enable;
},
/**
* !#en The size of the atlas that was created
* !#zh 创建的图集的宽高
* @property textureSize
* @type {Number}
*/
get textureSize () {
return _textureSize;
},
set textureSize (value) {
_textureSize = value;
},
/**
* !#en The maximum size of the picture that can be added to the atlas.
* !#zh 可以添加进图集的图片的最大尺寸。
* @property maxFrameSize
* @type {Number}
*/
get maxFrameSize () {
return _maxFrameSize;
},
set maxFrameSize (value) {
_maxFrameSize = value;
},
/**
* !#en The minimum size of the picture that can be added to the atlas.
* !#zh 可以添加进图集的图片的最小尺寸。
* @property minFrameSize
* @type {Number}
* @deprecated
*/
/**
* !#en Append a sprite frame into the dynamic atlas.
* !#zh 添加碎图进入动态图集。
* @method insertSpriteFrame
* @param {SpriteFrame} spriteFrame
*/
insertSpriteFrame (spriteFrame) {
if (CC_EDITOR) return null;
if (!_enabled || _atlasIndex === _maxAtlasCount ||
!spriteFrame || spriteFrame._original) return null;
if (!spriteFrame._texture.packable) return null;
let atlas = _atlases[_atlasIndex];
if (!atlas) {
atlas = newAtlas();
}
let frame = atlas.insertSpriteFrame(spriteFrame);
if (!frame && _atlasIndex !== _maxAtlasCount) {
atlas = newAtlas();
return atlas.insertSpriteFrame(spriteFrame);
}
return frame;
},
/**
* !#en Resets all dynamic atlas, and the existing ones will be destroyed.
* !#zh 重置所有动态图集,已有的动态图集会被销毁。
* @method reset
*/
reset () {
for (let i = 0, l = _atlases.length; i < l; i++) {
_atlases[i].destroy();
}
_atlases.length = 0;
_atlasIndex = -1;
},
deleteAtlasSpriteFrame (spriteFrame) {
if (!spriteFrame._original) return;
let texture = spriteFrame._original._texture;
this.deleteAtlasTexture(texture);
},
deleteAtlasTexture (texture) {
if (texture) {
for (let i = _atlases.length - 1; i >= 0; i--) {
_atlases[i].deleteInnerTexture(texture);
if (_atlases[i].isEmpty()) {
_atlases[i].destroy();
_atlases.splice(i, 1);
_atlasIndex--;
}
}
}
},
/**
* !#en Displays all the dynamic atlas in the current scene, which you can use to view the current atlas state.
* !#zh 在当前场景中显示所有动态图集,可以用来查看当前的合图状态。
* @method showDebug
* @param {Boolean} show
* @return {Node}
*/
showDebug (show) {
if (show) {
if (!_debugNode || !_debugNode.isValid) {
let width = cc.visibleRect.width;
let height = cc.visibleRect.height;
_debugNode = new cc.Node('DYNAMIC_ATLAS_DEBUG_NODE');
_debugNode.width = width;
_debugNode.height = height;
_debugNode.x = width/2;
_debugNode.y = height/2;
_debugNode.zIndex = cc.macro.MAX_ZINDEX;
_debugNode.parent = cc.director.getScene();
_debugNode.groupIndex = cc.Node.BuiltinGroupIndex.DEBUG;
cc.Camera._setupDebugCamera();
let scroll = _debugNode.addComponent(cc.ScrollView);
let content = new cc.Node('CONTENT');
let layout = content.addComponent(cc.Layout);
layout.type = cc.Layout.Type.VERTICAL;
layout.resizeMode = cc.Layout.ResizeMode.CONTAINER;
content.parent = _debugNode;
content.width = _textureSize;
content.anchorY = 1;
content.x = _textureSize;
scroll.content = content;
for (let i = 0; i <= _atlasIndex; i++) {
let node = new cc.Node('ATLAS');
let texture = _atlases[i]._texture;
let spriteFrame = new cc.SpriteFrame();
spriteFrame.setTexture(_atlases[i]._texture);
let sprite = node.addComponent(cc.Sprite);
sprite.spriteFrame = spriteFrame;
node.parent = content;
}
}
return _debugNode;
}
else {
if (_debugNode) {
_debugNode.parent = null;
_debugNode = null;
}
}
},
update () {
if (!this.enabled) return;
for (let i = 0; i <= _atlasIndex; i++) {
_atlases[i].update();
}
},
};
/**
* @module cc
*/
/**
* @property dynamicAtlasManager
* @type DynamicAtlasManager
*/
module.exports = cc.dynamicAtlasManager = dynamicAtlasManager;

View File

@@ -0,0 +1,689 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
import Assembler2D from '../../assembler-2d';
const textUtils = require('../../../utils/text-utils');
const macro = require('../../../platform/CCMacro');
const Label = require('../../../components/CCLabel');
const Overflow = Label.Overflow;
const shareLabelInfo = require('../utils').shareLabelInfo;
let LetterInfo = function() {
this.char = '';
this.valid = true;
this.x = 0;
this.y = 0;
this.line = 0;
this.hash = "";
};
let _tmpRect = cc.rect();
let _comp = null;
let _horizontalKernings = [];
let _lettersInfo = [];
let _linesWidth = [];
let _linesOffsetX = [];
let _fntConfig = null;
let _numberOfLines = 0;
let _textDesiredHeight = 0;
let _letterOffsetY = 0;
let _tailoredTopY = 0;
let _tailoredBottomY = 0;
let _bmfontScale = 1.0;
let _lineBreakWithoutSpaces = false;
let _spriteFrame = null;
let _lineSpacing = 0;
let _contentSize = cc.size();
let _string = '';
let _fontSize = 0;
let _originFontSize = 0;
let _hAlign = 0;
let _vAlign = 0;
let _spacingX = 0;
let _lineHeight = 0;
let _overflow = 0;
let _isWrapText = false;
let _labelWidth = 0;
let _labelHeight = 0;
let _maxLineWidth = 0;
export default class BmfontAssembler extends Assembler2D {
updateRenderData (comp) {
if (!comp._vertsDirty) return;
if (_comp === comp) return;
_comp = comp;
this._reserveQuads(comp, comp.string.toString().length);
this._updateFontFamily(comp);
this._updateProperties(comp);
this._updateLabelInfo(comp);
this._updateContent();
this.updateWorldVerts(comp);
_comp._actualFontSize = _fontSize;
_comp.node.setContentSize(_contentSize);
_comp._vertsDirty = false;
_comp = null;
this._resetProperties();
}
_updateFontScale () {
_bmfontScale = _fontSize / _originFontSize;
}
_updateFontFamily (comp) {
let fontAsset = comp.font;
_spriteFrame = fontAsset.spriteFrame;
_fntConfig = fontAsset._fntConfig;
shareLabelInfo.fontAtlas = fontAsset._fontDefDictionary;
this.packToDynamicAtlas(comp, _spriteFrame);
}
_updateLabelInfo() {
// clear
shareLabelInfo.hash = "";
shareLabelInfo.margin = 0;
}
_updateProperties (comp) {
_string = comp.string.toString();
_fontSize = comp.fontSize;
_originFontSize = _fntConfig ? _fntConfig.fontSize : comp.fontSize;
_hAlign = comp.horizontalAlign;
_vAlign = comp.verticalAlign;
_spacingX = comp.spacingX;
_overflow = comp.overflow;
_lineHeight = comp._lineHeight;
_contentSize.width = comp.node.width;
_contentSize.height = comp.node.height;
// should wrap text
if (_overflow === Overflow.NONE) {
_isWrapText = false;
_contentSize.width += shareLabelInfo.margin * 2;
_contentSize.height += shareLabelInfo.margin * 2;
}
else if (_overflow === Overflow.RESIZE_HEIGHT) {
_isWrapText = true;
_contentSize.height += shareLabelInfo.margin * 2;
}
else {
_isWrapText = comp.enableWrapText;
}
shareLabelInfo.lineHeight = _lineHeight;
shareLabelInfo.fontSize = _fontSize;
this._setupBMFontOverflowMetrics();
}
_resetProperties () {
_fntConfig = null;
_spriteFrame = null;
shareLabelInfo.hash = "";
shareLabelInfo.margin = 0;
}
_updateContent () {
this._updateFontScale();
this._computeHorizontalKerningForText();
this._alignText();
}
_computeHorizontalKerningForText () {
let string = _string;
let stringLen = string.length;
let horizontalKernings = _horizontalKernings;
let kerningDict;
_fntConfig && (kerningDict = _fntConfig.kerningDict);
if (kerningDict && !cc.js.isEmptyObject(kerningDict)) {
let prev = -1;
for (let i = 0; i < stringLen; ++i) {
let key = string.charCodeAt(i);
let kerningAmount = kerningDict[(prev << 16) | (key & 0xffff)] || 0;
if (i < stringLen - 1) {
horizontalKernings[i] = kerningAmount;
} else {
horizontalKernings[i] = 0;
}
prev = key;
}
} else {
horizontalKernings.length = 0;
}
}
_multilineTextWrap (nextTokenFunc) {
let textLen = _string.length;
let lineIndex = 0;
let nextTokenX = 0;
let nextTokenY = 0;
let longestLine = 0;
let letterRight = 0;
let highestY = 0;
let lowestY = 0;
let letterDef = null;
let letterPosition = cc.v2(0, 0);
for (let index = 0; index < textLen;) {
let character = _string.charAt(index);
if (character === "\n") {
_linesWidth.push(letterRight);
letterRight = 0;
lineIndex++;
nextTokenX = 0;
nextTokenY -= _lineHeight * this._getFontScale() + _lineSpacing;
this._recordPlaceholderInfo(index, character);
index++;
continue;
}
let tokenLen = nextTokenFunc(_string, index, textLen);
let tokenHighestY = highestY;
let tokenLowestY = lowestY;
let tokenRight = letterRight;
let nextLetterX = nextTokenX;
let newLine = false;
for (let tmp = 0; tmp < tokenLen; ++tmp) {
let letterIndex = index + tmp;
character = _string.charAt(letterIndex);
if (character === "\r") {
this._recordPlaceholderInfo(letterIndex, character);
continue;
}
letterDef = shareLabelInfo.fontAtlas.getLetterDefinitionForChar(character, shareLabelInfo);
if (!letterDef) {
this._recordPlaceholderInfo(letterIndex, character);
let atlasName = "";
_fntConfig && (atlasName = _fntConfig.atlasName);
console.log("Can't find letter definition in texture atlas " + atlasName + " for letter:" + character);
continue;
}
let letterX = nextLetterX + letterDef.offsetX * _bmfontScale - shareLabelInfo.margin;
if (_isWrapText
&& _maxLineWidth > 0
&& nextTokenX > 0
&& letterX + letterDef.w * _bmfontScale > _maxLineWidth
&& !textUtils.isUnicodeSpace(character)) {
_linesWidth.push(letterRight);
letterRight = 0;
lineIndex++;
nextTokenX = 0;
nextTokenY -= (_lineHeight * this._getFontScale() + _lineSpacing);
newLine = true;
break;
} else {
letterPosition.x = letterX;
}
letterPosition.y = nextTokenY - letterDef.offsetY * _bmfontScale + shareLabelInfo.margin;
this._recordLetterInfo(letterPosition, character, letterIndex, lineIndex);
if (letterIndex + 1 < _horizontalKernings.length && letterIndex < textLen - 1) {
nextLetterX += _horizontalKernings[letterIndex + 1];
}
nextLetterX += letterDef.xAdvance * _bmfontScale + _spacingX - shareLabelInfo.margin * 2;
tokenRight = letterPosition.x + letterDef.w * _bmfontScale - shareLabelInfo.margin;
if (tokenHighestY < letterPosition.y) {
tokenHighestY = letterPosition.y;
}
if (tokenLowestY > letterPosition.y - letterDef.h * _bmfontScale) {
tokenLowestY = letterPosition.y - letterDef.h * _bmfontScale;
}
} //end of for loop
if (newLine) continue;
nextTokenX = nextLetterX;
letterRight = tokenRight;
if (highestY < tokenHighestY) {
highestY = tokenHighestY;
}
if (lowestY > tokenLowestY) {
lowestY = tokenLowestY;
}
if (longestLine < letterRight) {
longestLine = letterRight;
}
index += tokenLen;
} //end of for loop
_linesWidth.push(letterRight);
_numberOfLines = lineIndex + 1;
_textDesiredHeight = _numberOfLines * _lineHeight * this._getFontScale();
if (_numberOfLines > 1) {
_textDesiredHeight += (_numberOfLines - 1) * _lineSpacing;
}
_contentSize.width = _labelWidth;
_contentSize.height = _labelHeight;
if (_labelWidth <= 0) {
_contentSize.width = parseFloat(longestLine.toFixed(2)) + shareLabelInfo.margin * 2;
}
if (_labelHeight <= 0) {
_contentSize.height = parseFloat(_textDesiredHeight.toFixed(2)) + shareLabelInfo.margin * 2;
}
_tailoredTopY = _contentSize.height;
_tailoredBottomY = 0;
if (_overflow !== Overflow.CLAMP) {
if (highestY > 0) {
_tailoredTopY = _contentSize.height + highestY;
}
if (lowestY < -_textDesiredHeight) {
_tailoredBottomY = _textDesiredHeight + lowestY;
}
}
return true;
}
_getFirstCharLen () {
return 1;
}
_getFontScale () {
return _overflow === Overflow.SHRINK ? _bmfontScale : 1;
}
_getFirstWordLen (text, startIndex, textLen) {
let character = text.charAt(startIndex);
if (textUtils.isUnicodeCJK(character)
|| character === "\n"
|| textUtils.isUnicodeSpace(character)) {
return 1;
}
let len = 1;
let letterDef = shareLabelInfo.fontAtlas.getLetterDefinitionForChar(character, shareLabelInfo);
if (!letterDef) {
return len;
}
let nextLetterX = letterDef.xAdvance * _bmfontScale + _spacingX;
let letterX;
for (let index = startIndex + 1; index < textLen; ++index) {
character = text.charAt(index);
letterDef = shareLabelInfo.fontAtlas.getLetterDefinitionForChar(character, shareLabelInfo);
if (!letterDef) {
break;
}
letterX = nextLetterX + letterDef.offsetX * _bmfontScale;
if(letterX + letterDef.w * _bmfontScale > _maxLineWidth
&& !textUtils.isUnicodeSpace(character)
&& _maxLineWidth > 0) {
return len;
}
nextLetterX += letterDef.xAdvance * _bmfontScale + _spacingX;
if (character === "\n"
|| textUtils.isUnicodeSpace(character)
|| textUtils.isUnicodeCJK(character)) {
break;
}
len++;
}
return len;
}
_multilineTextWrapByWord () {
return this._multilineTextWrap(this._getFirstWordLen);
}
_multilineTextWrapByChar () {
return this._multilineTextWrap(this._getFirstCharLen);
}
_recordPlaceholderInfo (letterIndex, char) {
if (letterIndex >= _lettersInfo.length) {
let tmpInfo = new LetterInfo();
_lettersInfo.push(tmpInfo);
}
_lettersInfo[letterIndex].char = char;
_lettersInfo[letterIndex].hash = char.charCodeAt(0) + shareLabelInfo.hash;
_lettersInfo[letterIndex].valid = false;
}
_recordLetterInfo (letterPosition, character, letterIndex, lineIndex) {
if (letterIndex >= _lettersInfo.length) {
let tmpInfo = new LetterInfo();
_lettersInfo.push(tmpInfo);
}
let char = character.charCodeAt(0);
let key = char + shareLabelInfo.hash;
_lettersInfo[letterIndex].line= lineIndex;
_lettersInfo[letterIndex].char = character;
_lettersInfo[letterIndex].hash = key;
_lettersInfo[letterIndex].valid = shareLabelInfo.fontAtlas.getLetter(key).valid;
_lettersInfo[letterIndex].x = letterPosition.x;
_lettersInfo[letterIndex].y = letterPosition.y;
}
_alignText () {
_textDesiredHeight = 0;
_linesWidth.length = 0;
if (!_lineBreakWithoutSpaces) {
this._multilineTextWrapByWord();
} else {
this._multilineTextWrapByChar();
}
this._computeAlignmentOffset();
//shrink
if (_overflow === Overflow.SHRINK) {
if (_fontSize > 0 && this._isVerticalClamp()) {
this._shrinkLabelToContentSize(this._isVerticalClamp);
}
}
if (!this._updateQuads()) {
if (_overflow === Overflow.SHRINK) {
this._shrinkLabelToContentSize(this._isHorizontalClamp);
}
}
}
_scaleFontSizeDown (fontSize) {
let shouldUpdateContent = true;
if (!fontSize) {
fontSize = 0.1;
shouldUpdateContent = false;
}
_fontSize = fontSize;
if (shouldUpdateContent) {
this._updateContent();
}
}
_shrinkLabelToContentSize (lambda) {
let fontSize = _fontSize;
let left = 0, right = fontSize | 0, mid = 0;
while (left < right) {
mid = (left + right + 1) >> 1;
let newFontSize = mid;
if (newFontSize <= 0) {
break;
}
_bmfontScale = newFontSize / _originFontSize;
if (!_lineBreakWithoutSpaces) {
this._multilineTextWrapByWord();
} else {
this._multilineTextWrapByChar();
}
this._computeAlignmentOffset();
if (lambda()) {
right = mid - 1;
} else {
left = mid;
}
}
let actualFontSize = left;
if (actualFontSize >= 0) {
this._scaleFontSizeDown(actualFontSize);
}
}
_isVerticalClamp () {
if (_textDesiredHeight > _contentSize.height) {
return true;
} else {
return false;
}
}
_isHorizontalClamp () {
let letterClamp = false;
for (let ctr = 0, l = _string.length; ctr < l; ++ctr) {
let letterInfo = _lettersInfo[ctr];
if (letterInfo.valid) {
let letterDef = shareLabelInfo.fontAtlas.getLetter(letterInfo.hash);
let px = letterInfo.x + letterDef.w * _bmfontScale;
let lineIndex = letterInfo.line;
if (_labelWidth > 0) {
if (!_isWrapText) {
if(px > _contentSize.width){
letterClamp = true;
break;
}
}else{
let wordWidth = _linesWidth[lineIndex];
if (wordWidth > _contentSize.width && (px > _contentSize.width || px < 0)) {
letterClamp = true;
break;
}
}
}
}
}
return letterClamp;
}
_isHorizontalClamped (px, lineIndex) {
let wordWidth = _linesWidth[lineIndex];
let letterOverClamp = (px > _contentSize.width || px < 0);
if(!_isWrapText){
return letterOverClamp;
}else{
return (wordWidth > _contentSize.width && letterOverClamp);
}
}
_updateQuads () {
let texture = _spriteFrame ? _spriteFrame._texture : shareLabelInfo.fontAtlas.getTexture();
let node = _comp.node;
this.verticesCount = this.indicesCount = 0;
// Need to reset dataLength in Canvas rendering mode.
this._renderData && (this._renderData.dataLength = 0);
let contentSize = _contentSize,
appx = node._anchorPoint.x * contentSize.width,
appy = node._anchorPoint.y * contentSize.height;
let ret = true;
for (let ctr = 0, l = _string.length; ctr < l; ++ctr) {
let letterInfo = _lettersInfo[ctr];
if (!letterInfo.valid) continue;
let letterDef = shareLabelInfo.fontAtlas.getLetter(letterInfo.hash);
_tmpRect.height = letterDef.h;
_tmpRect.width = letterDef.w;
_tmpRect.x = letterDef.u;
_tmpRect.y = letterDef.v;
let py = letterInfo.y + _letterOffsetY;
if (_labelHeight > 0) {
if (py > _tailoredTopY) {
let clipTop = py - _tailoredTopY;
_tmpRect.y += clipTop;
_tmpRect.height -= clipTop;
py = py - clipTop;
}
if ((py - letterDef.h * _bmfontScale < _tailoredBottomY) && _overflow === Overflow.CLAMP) {
_tmpRect.height = (py < _tailoredBottomY) ? 0 : (py - _tailoredBottomY) / _bmfontScale;
}
}
let lineIndex = letterInfo.line;
let px = letterInfo.x + letterDef.w / 2 * _bmfontScale + _linesOffsetX[lineIndex];
if (_labelWidth > 0) {
if (this._isHorizontalClamped(px, lineIndex)) {
if (_overflow === Overflow.CLAMP) {
_tmpRect.width = 0;
} else if (_overflow === Overflow.SHRINK) {
if (_contentSize.width > letterDef.w) {
ret = false;
break;
} else {
_tmpRect.width = 0;
}
}
}
}
if (_tmpRect.height > 0 && _tmpRect.width > 0) {
let isRotated = this._determineRect(_tmpRect);
let letterPositionX = letterInfo.x + _linesOffsetX[letterInfo.line];
this.appendQuad(_comp, texture, _tmpRect, isRotated, letterPositionX - appx, py - appy, _bmfontScale);
}
}
this._quadsUpdated(_comp);
return ret;
}
_determineRect (tempRect) {
let isRotated = _spriteFrame.isRotated();
let originalSize = _spriteFrame._originalSize;
let rect = _spriteFrame._rect;
let offset = _spriteFrame._offset;
let trimmedLeft = offset.x + (originalSize.width - rect.width) / 2;
let trimmedTop = offset.y - (originalSize.height - rect.height) / 2;
if(!isRotated) {
tempRect.x += (rect.x - trimmedLeft);
tempRect.y += (rect.y + trimmedTop);
} else {
let originalX = tempRect.x;
tempRect.x = rect.x + rect.height - tempRect.y - tempRect.height - trimmedTop;
tempRect.y = originalX + rect.y - trimmedLeft;
if (tempRect.y < 0) {
tempRect.height = tempRect.height + trimmedTop;
}
}
return isRotated;
}
_computeAlignmentOffset () {
_linesOffsetX.length = 0;
switch (_hAlign) {
case macro.TextAlignment.LEFT:
for (let i = 0; i < _numberOfLines; ++i) {
_linesOffsetX.push(0);
}
break;
case macro.TextAlignment.CENTER:
for (let i = 0, l = _linesWidth.length; i < l; i++) {
_linesOffsetX.push((_contentSize.width - _linesWidth[i]) / 2);
}
break;
case macro.TextAlignment.RIGHT:
for (let i = 0, l = _linesWidth.length; i < l; i++) {
_linesOffsetX.push(_contentSize.width - _linesWidth[i]);
}
break;
default:
break;
}
// TOP
_letterOffsetY = _contentSize.height;
if (_vAlign !== macro.VerticalTextAlignment.TOP) {
let blank = _contentSize.height - _textDesiredHeight + _lineHeight * this._getFontScale() - _originFontSize * _bmfontScale;
if (_vAlign === macro.VerticalTextAlignment.BOTTOM) {
// BOTTOM
_letterOffsetY -= blank;
} else {
// CENTER:
_letterOffsetY -= blank / 2;
}
}
}
_setupBMFontOverflowMetrics () {
let newWidth = _contentSize.width,
newHeight = _contentSize.height;
if (_overflow === Overflow.RESIZE_HEIGHT) {
newHeight = 0;
}
if (_overflow === Overflow.NONE) {
newWidth = 0;
newHeight = 0;
}
_labelWidth = newWidth;
_labelHeight = newHeight;
_maxLineWidth = newWidth;
}
updateWorldVerts() {}
appendQuad (comp, texture, rect, rotated, x, y, scale) {}
_quadsUpdated (comp) {}
_reserveQuads () {}
}

View File

@@ -0,0 +1,118 @@
/****************************************************************************
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.
****************************************************************************/
/**
* !#en Class for Label Frame.
* !#zh LabelFrame
*/
function LabelFrame () {
// the location of the label on rendering texture
this._rect = null;
// uv data of frame
this.uv = [];
// texture of frame
this._texture = null;
// store original info before packed to dynamic atlas
this._original = null;
}
LabelFrame.prototype = {
constructor: LabelFrame,
/**
* !#en Returns the rect of the label frame in the texture.
* !#zh 获取 LabelFrame 的纹理矩形区域
* @method getRect
* @return {Rect}
*/
getRect: function () {
return cc.rect(this._rect);
},
/**
* !#en Sets the rect of the label frame in the texture.
* !#zh 设置 LabelFrame 的纹理矩形区域
* @method setRect
* @param {Rect} rect
*/
setRect: function (rect) {
this._rect = rect;
if (this._texture)
this._calculateUV();
},
_setDynamicAtlasFrame (frame) {
if (!frame) return;
this._original = {
_texture : this._texture,
_x : this._rect.x,
_y : this._rect.y
}
this._texture = frame.texture;
this._rect.x = frame.x;
this._rect.y = frame.y;
this._calculateUV();
},
_resetDynamicAtlasFrame () {
if (!this._original) return;
this._rect.x = this._original._x;
this._rect.y = this._original._y;
this._texture = this._original._texture;
this._original = null;
this._calculateUV();
},
_refreshTexture: function (texture) {
this._texture = texture;
this._rect = cc.rect(0, 0, texture.width, texture.height);
this._calculateUV();
},
_calculateUV() {
let rect = this._rect,
texture = this._texture,
uv = this.uv,
texw = texture.width,
texh = texture.height;
let l = texw === 0 ? 0 : rect.x / texw;
let r = texw === 0 ? 0 : (rect.x + rect.width) / texw;
let b = texh === 0 ? 0 : (rect.y + rect.height) / texh;
let t = texh === 0 ? 0 : rect.y / texh;
uv[0] = l;
uv[1] = b;
uv[2] = r;
uv[3] = b;
uv[4] = l;
uv[5] = t;
uv[6] = r;
uv[7] = t;
}
}
module.exports = LabelFrame;

View File

@@ -0,0 +1,313 @@
/****************************************************************************
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.
****************************************************************************/
import WebglBmfontAssembler from '../../webgl/assemblers/label/2d/bmfont';
const Label = require('../../../components/CCLabel');
const LabelOutline = require('../../../components/CCLabelOutline');
const textUtils = require('../../../utils/text-utils');
const Component = require('../../../components/CCComponent');
const RenderTexture = require('../../../assets/CCRenderTexture');
const OUTLINE_SUPPORTED = cc.js.isChildClassOf(LabelOutline, Component);
const getFontFamily = require('../utils').getFontFamily;
const shareLabelInfo = require('../utils').shareLabelInfo;
const FontLetterDefinition = cc.BitmapFont.FontLetterDefinition;
const FontAtlas = cc.BitmapFont.FontAtlas;
const WHITE = cc.Color.WHITE;
const space = 0;
const bleed = 2;
const _invisibleAlpha = (1 / 255).toFixed(3);
function LetterTexture(char, labelInfo) {
this._texture = null;
this._labelInfo = labelInfo;
this._char = char;
this._hash = null;
this._data = null;
this._canvas = null;
this._context = null;
this._width = 0;
this._height = 0;
this._offsetY = 0;
this._hash = char.charCodeAt(0) + labelInfo.hash;
}
LetterTexture.prototype = {
constructor: LetterTexture,
updateRenderData () {
this._updateProperties();
this._updateTexture();
},
_updateProperties () {
this._texture = new cc.Texture2D();
this._data = Label._canvasPool.get();
this._canvas = this._data.canvas;
this._context = this._data.context;
this._context.font = this._labelInfo.fontDesc;
let width = textUtils.safeMeasureText(this._context, this._char, this._labelInfo.fontDesc);
let blank = this._labelInfo.margin * 2 + bleed;
this._width = parseFloat(width.toFixed(2)) + blank;
this._height = (1 + textUtils.BASELINE_RATIO) * this._labelInfo.fontSize + blank;
this._offsetY = - (this._labelInfo.fontSize * textUtils.BASELINE_RATIO) / 2;
if (this._canvas.width !== this._width) {
this._canvas.width = this._width;
}
if (this._canvas.height !== this._height) {
this._canvas.height = this._height;
}
this._texture.initWithElement(this._canvas);
},
_updateTexture () {
let context = this._context;
let labelInfo = this._labelInfo,
width = this._canvas.width,
height = this._canvas.height;
const fontSize = this._labelInfo.fontSize;
let startX = width / 2;
let startY = height / 2 + fontSize * textUtils.MIDDLE_RATIO + fontSize * textUtils.BASELINE_OFFSET;
let color = labelInfo.color;
// use round for line join to avoid sharp intersect point
context.lineJoin = 'round';
context.textAlign = 'center';
context.clearRect(0, 0, width, height);
//Add a white background to avoid black edges.
context.fillStyle = `rgba(${color.r}, ${color.g}, ${color.b}, ${_invisibleAlpha})`;
context.fillRect(0, 0, width, height);
context.font = labelInfo.fontDesc;
context.fillStyle = `rgba(${color.r}, ${color.g}, ${color.b}, 1)`;
if (labelInfo.isOutlined && labelInfo.margin > 0) {
let strokeColor = labelInfo.out || WHITE;
context.strokeStyle = `rgba(${strokeColor.r}, ${strokeColor.g}, ${strokeColor.b}, ${strokeColor.a / 255})`;
context.lineWidth = labelInfo.margin * 2;
context.strokeText(this._char, startX, startY);
}
context.fillText(this._char, startX, startY);
this._texture.handleLoadedTexture();
},
destroy () {
this._texture.destroy();
this._texture = null;
Label._canvasPool.put(this._data);
},
}
function LetterAtlas (width, height) {
let texture = new RenderTexture();
texture.initWithSize(width, height);
texture.update();
this._fontDefDictionary = new FontAtlas(texture);
this._x = space;
this._y = space;
this._nexty = space;
this._width = width;
this._height = height;
cc.director.on(cc.Director.EVENT_BEFORE_SCENE_LAUNCH, this.beforeSceneLoad, this);
}
cc.js.mixin(LetterAtlas.prototype, {
insertLetterTexture (letterTexture) {
let texture = letterTexture._texture;
let width = texture.width, height = texture.height;
if ((this._x + width + space) > this._width) {
this._x = space;
this._y = this._nexty;
}
if ((this._y + height) > this._nexty) {
this._nexty = this._y + height + space;
}
if (this._nexty > this._height) {
return null;
}
this._fontDefDictionary._texture.drawTextureAt(texture, this._x, this._y);
this._dirty = true;
let letter = new FontLetterDefinition();
letter.u = this._x + bleed/2;
letter.v = this._y + bleed/2;
letter.texture = this._fontDefDictionary._texture;
letter.valid = true;
letter.w = letterTexture._width - bleed;
letter.h = letterTexture._height - bleed;
letter.xAdvance = letter.w;
letter.offsetY = letterTexture._offsetY;
this._x += width + space;
this._fontDefDictionary.addLetterDefinitions(letterTexture._hash, letter);
return letter
},
update () {
if (!this._dirty) return;
this._fontDefDictionary._texture.update();
this._dirty = false;
},
reset () {
this._x = space;
this._y = space;
this._nexty = space;
let chars = this._fontDefDictionary._letterDefinitions;
for (let i = 0, l = chars.length; i < l; i++) {
let char = chars[i];
if (!char.isValid) {
continue;
}
char.destroy();
}
this._fontDefDictionary.clear();
},
destroy () {
this.reset();
this._fontDefDictionary._texture.destroy();
this._fontDefDictionary._texture = null;
},
beforeSceneLoad () {
this.clearAllCache();
},
clearAllCache () {
this.destroy();
let texture = new RenderTexture();
texture.initWithSize(this._width, this._height);
texture.update();
this._fontDefDictionary._texture = texture;
},
getLetter (key) {
return this._fontDefDictionary._letterDefinitions[key];
},
getTexture () {
return this._fontDefDictionary.getTexture();
},
getLetterDefinitionForChar: function(char, labelInfo) {
let hash = char.charCodeAt(0) + labelInfo.hash;
let letter = this._fontDefDictionary._letterDefinitions[hash];
if (!letter) {
let temp = new LetterTexture(char, labelInfo);
temp.updateRenderData();
letter = this.insertLetterTexture(temp);
temp.destroy();
}
return letter;
}
});
function computeHash (labelInfo) {
let hashData = '';
let color = labelInfo.color.toHEX();
let out = '';
if (labelInfo.isOutlined && labelInfo.margin > 0) {
out = out + labelInfo.margin + labelInfo.out.toHEX();
}
return hashData + labelInfo.fontSize + labelInfo.fontFamily + color + out;
}
let _shareAtlas = null;
let _atlasWidth = 2048;
let _atlasHeight = 2048;
let _isBold = false;
export default class LetterFontAssembler extends WebglBmfontAssembler {
_getAssemblerData () {
if (!_shareAtlas) {
_shareAtlas = new LetterAtlas(_atlasWidth, _atlasHeight);
cc.Label._shareAtlas = _shareAtlas;
}
return _shareAtlas.getTexture();
}
_updateFontFamily (comp) {
shareLabelInfo.fontAtlas = _shareAtlas;
shareLabelInfo.fontFamily = getFontFamily(comp);
// outline
let outline = OUTLINE_SUPPORTED && comp.getComponent(LabelOutline);
if (outline && outline.enabled) {
shareLabelInfo.isOutlined = true;
shareLabelInfo.margin = outline.width;
shareLabelInfo.out = outline.color.clone();
shareLabelInfo.out.a = outline.color.a * comp.node.color.a / 255.0;
}
else {
shareLabelInfo.isOutlined = false;
shareLabelInfo.margin = 0;
}
}
_updateLabelInfo (comp) {
shareLabelInfo.fontDesc = this._getFontDesc();
shareLabelInfo.color = comp.node.color;
shareLabelInfo.hash = computeHash(shareLabelInfo);
}
_getFontDesc () {
let fontDesc = shareLabelInfo.fontSize.toString() + 'px ';
fontDesc = fontDesc + shareLabelInfo.fontFamily;
if (_isBold) {
fontDesc = "bold " + fontDesc;
}
return fontDesc;
}
_computeHorizontalKerningForText () {}
_determineRect (tempRect) {
return false;
}
}

View File

@@ -0,0 +1,545 @@
/****************************************************************************
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 Assembler2D from '../../assembler-2d';
let textUtils = require('../../../utils/text-utils');
const macro = require('../../../platform/CCMacro');
const Label = require('../../../components/CCLabel');
const LabelOutline = require('../../../components/CCLabelOutline');
const LabelShadow = require('../../../components/CCLabelShadow');
const Overflow = Label.Overflow;
const deleteFromDynamicAtlas = require('../utils').deleteFromDynamicAtlas;
const getFontFamily = require('../utils').getFontFamily;
const _invisibleAlpha = (1 / 255).toFixed(3);
const MAX_SIZE = 2048;
let _context = null;
let _canvas = null;
let _texture = null;
let _fontDesc = '';
let _string = '';
let _fontSize = 0;
let _drawFontSize = 0;
let _splitedStrings = [];
let _canvasSize = cc.Size.ZERO;
let _lineHeight = 0;
let _hAlign = 0;
let _vAlign = 0;
let _color = null;
let _fontFamily = '';
let _overflow = Overflow.NONE;
let _isWrapText = false;
let _premultiply = false;
// outline
let _outlineComp = null;
let _outlineColor = cc.Color.WHITE;
// shadow
let _shadowComp = null;
let _shadowColor = cc.Color.BLACK;
let _canvasPadding = cc.rect();
let _contentSizeExtend = cc.Size.ZERO;
let _nodeContentSize = cc.Size.ZERO;
let _enableBold = false;
let _enableItalic = false;
let _enableUnderline = false;
let _underlineThickness = 0;
let _drawUnderlinePos = cc.Vec2.ZERO;
let _drawUnderlineWidth = 0;
let _sharedLabelData;
const Alignment = [
'left', // macro.TextAlignment.LEFT
'center', // macro.TextAlignment.CENTER
'right' // macro.TextAlignment.RIGHT
];
export default class TTFAssembler extends Assembler2D {
_getAssemblerData () {
_sharedLabelData = Label._canvasPool.get();
_sharedLabelData.canvas.width = _sharedLabelData.canvas.height = 1;
return _sharedLabelData;
}
_resetAssemblerData (assemblerData) {
if (assemblerData) {
Label._canvasPool.put(assemblerData);
}
}
updateRenderData (comp) {
super.updateRenderData(comp);
if (!comp._vertsDirty) return;
this._updateProperties(comp);
this._calculateLabelFont();
this._updateLabelDimensions();
this._updateTexture(comp);
this._calDynamicAtlas(comp);
comp._actualFontSize = _fontSize;
comp.node.setContentSize(_nodeContentSize);
this.updateVerts(comp);
comp._vertsDirty = false;
_context = null;
_canvas = null;
_texture = null;
}
updateVerts () {
}
_updatePaddingRect () {
let top = 0, bottom = 0, left = 0, right = 0;
let outlineWidth = 0;
_contentSizeExtend.width = _contentSizeExtend.height = 0;
if (_outlineComp) {
outlineWidth = _outlineComp.width;
top = bottom = left = right = outlineWidth;
_contentSizeExtend.width = _contentSizeExtend.height = outlineWidth * 2;
}
if (_shadowComp) {
let shadowWidth = _shadowComp.blur + outlineWidth;
left = Math.max(left, -_shadowComp._offset.x + shadowWidth);
right = Math.max(right, _shadowComp._offset.x + shadowWidth);
top = Math.max(top, _shadowComp._offset.y + shadowWidth);
bottom = Math.max(bottom, -_shadowComp._offset.y + shadowWidth);
}
if (_enableItalic) {
//0.0174532925 = 3.141592653 / 180
let offset = _drawFontSize * Math.tan(12 * 0.0174532925);
right += offset;
_contentSizeExtend.width += offset;
}
_canvasPadding.x = left;
_canvasPadding.y = top;
_canvasPadding.width = left + right;
_canvasPadding.height = top + bottom;
}
_updateProperties (comp) {
let assemblerData = comp._assemblerData;
_context = assemblerData.context;
_canvas = assemblerData.canvas;
_texture = comp._frame._original ? comp._frame._original._texture : comp._frame._texture;
_string = comp.string.toString();
_fontSize = comp._fontSize;
_drawFontSize = _fontSize;
_underlineThickness = comp.underlineHeight || _drawFontSize / 8;
_overflow = comp.overflow;
_canvasSize.width = comp.node.width;
_canvasSize.height = comp.node.height;
_nodeContentSize = comp.node.getContentSize();
_lineHeight = comp._lineHeight;
_hAlign = comp.horizontalAlign;
_vAlign = comp.verticalAlign;
_color = comp.node.color;
_enableBold = comp.enableBold;
_enableItalic = comp.enableItalic;
_enableUnderline = comp.enableUnderline;
_fontFamily = getFontFamily(comp);
_premultiply = comp.srcBlendFactor === cc.macro.BlendFactor.ONE;
if (CC_NATIVERENDERER) {
_context._setPremultiply(_premultiply);
}
if (_overflow === Overflow.NONE) {
_isWrapText = false;
}
else if (_overflow === Overflow.RESIZE_HEIGHT) {
_isWrapText = true;
}
else {
_isWrapText = comp.enableWrapText;
}
// outline
_outlineComp = LabelOutline && comp.getComponent(LabelOutline);
_outlineComp = (_outlineComp && _outlineComp.enabled && _outlineComp.width > 0) ? _outlineComp : null;
if (_outlineComp) {
_outlineColor.set(_outlineComp.color);
}
// shadow
_shadowComp = LabelShadow && comp.getComponent(LabelShadow);
_shadowComp = (_shadowComp && _shadowComp.enabled) ? _shadowComp : null;
if (_shadowComp) {
_shadowColor.set(_shadowComp.color);
// TODO: temporary solution, cascade opacity for outline color
_shadowColor.a = _shadowColor.a * comp.node.color.a / 255.0;
}
this._updatePaddingRect();
}
_calculateFillTextStartPosition () {
let labelX = 0;
if (_hAlign === macro.TextAlignment.RIGHT) {
labelX = _canvasSize.width - _canvasPadding.width;
} else if (_hAlign === macro.TextAlignment.CENTER) {
labelX = (_canvasSize.width - _canvasPadding.width) / 2;
}
let lineHeight = this._getLineHeight();
let drawStartY = lineHeight * (_splitedStrings.length - 1);
// TOP
let firstLinelabelY = _fontSize * (1 - textUtils.BASELINE_RATIO / 2);
if (_vAlign !== macro.VerticalTextAlignment.TOP) {
// free space in vertical direction
let blank = drawStartY + _canvasPadding.height + _fontSize - _canvasSize.height;
if (_vAlign === macro.VerticalTextAlignment.BOTTOM) {
// Unlike BMFont, needs to reserve space below.
blank += textUtils.BASELINE_RATIO / 2 * _fontSize;
// BOTTOM
firstLinelabelY -= blank;
} else {
// CENTER
firstLinelabelY -= blank / 2;
}
}
firstLinelabelY += textUtils.BASELINE_OFFSET * _fontSize;
return cc.v2(labelX + _canvasPadding.x, firstLinelabelY + _canvasPadding.y);
}
_setupOutline () {
_context.strokeStyle = `rgba(${_outlineColor.r}, ${_outlineColor.g}, ${_outlineColor.b}, ${_outlineColor.a / 255})`;
_context.lineWidth = _outlineComp.width * 2;
}
_setupShadow () {
_context.shadowColor = `rgba(${_shadowColor.r}, ${_shadowColor.g}, ${_shadowColor.b}, ${_shadowColor.a / 255})`;
_context.shadowBlur = _shadowComp.blur;
_context.shadowOffsetX = _shadowComp.offset.x;
_context.shadowOffsetY = -_shadowComp.offset.y;
}
_drawTextEffect (startPosition, lineHeight) {
if (!_shadowComp && !_outlineComp && !_enableUnderline) return;
let isMultiple = _splitedStrings.length > 1 && _shadowComp;
let measureText = this._measureText(_context, _fontDesc);
let drawTextPosX = 0, drawTextPosY = 0;
// only one set shadow and outline
if (_shadowComp) {
this._setupShadow();
}
if (_outlineComp) {
this._setupOutline();
}
// draw shadow and (outline or text)
for (let i = 0; i < _splitedStrings.length; ++i) {
drawTextPosX = startPosition.x;
drawTextPosY = startPosition.y + i * lineHeight;
// multiple lines need to be drawn outline and fill text
if (isMultiple) {
if (_outlineComp) {
_context.strokeText(_splitedStrings[i], drawTextPosX, drawTextPosY);
}
_context.fillText(_splitedStrings[i], drawTextPosX, drawTextPosY);
}
// draw underline
if (_enableUnderline) {
_drawUnderlineWidth = measureText(_splitedStrings[i]);
if (_hAlign === macro.TextAlignment.RIGHT) {
_drawUnderlinePos.x = startPosition.x - _drawUnderlineWidth;
} else if (_hAlign === macro.TextAlignment.CENTER) {
_drawUnderlinePos.x = startPosition.x - (_drawUnderlineWidth / 2);
} else {
_drawUnderlinePos.x = startPosition.x;
}
_drawUnderlinePos.y = drawTextPosY + _drawFontSize / 8;
_context.fillRect(_drawUnderlinePos.x, _drawUnderlinePos.y, _drawUnderlineWidth, _underlineThickness);
}
}
if (isMultiple) {
_context.shadowColor = 'transparent';
}
}
_updateTexture () {
_context.clearRect(0, 0, _canvas.width, _canvas.height);
// use round for line join to avoid sharp intersect point
_context.lineJoin = 'round';
//Add a white background to avoid black edges.
if (!_premultiply) {
//TODO: it is best to add alphaTest to filter out the background color.
let _fillColor = _outlineComp ? _outlineColor : _color;
_context.fillStyle = `rgba(${_fillColor.r}, ${_fillColor.g}, ${_fillColor.b}, ${_invisibleAlpha})`;
_context.fillRect(0, 0, _canvas.width, _canvas.height);
_context.fillStyle = `rgba(${_color.r}, ${_color.g}, ${_color.b}, 1)`;
} else {
_context.fillStyle = `rgba(${_color.r}, ${_color.g}, ${_color.b}, ${_color.a / 255.0})`;
}
let startPosition = this._calculateFillTextStartPosition();
let lineHeight = this._getLineHeight();
let drawTextPosX = startPosition.x, drawTextPosY = 0;
// draw shadow and underline
this._drawTextEffect(startPosition, lineHeight);
// draw text and outline
for (let i = 0; i < _splitedStrings.length; ++i) {
drawTextPosY = startPosition.y + i * lineHeight;
if (_outlineComp) {
_context.strokeText(_splitedStrings[i], drawTextPosX, drawTextPosY);
}
_context.fillText(_splitedStrings[i], drawTextPosX, drawTextPosY);
}
if (_shadowComp) {
_context.shadowColor = 'transparent';
}
_texture.handleLoadedTexture();
}
_calDynamicAtlas (comp) {
if(comp.cacheMode !== Label.CacheMode.BITMAP) return;
let frame = comp._frame;
// Delete cache in atlas.
deleteFromDynamicAtlas(comp, frame);
if (!frame._original) {
frame.setRect(cc.rect(0, 0, _canvas.width, _canvas.height));
}
this.packToDynamicAtlas(comp, frame);
}
_updateLabelDimensions () {
let maxTextureSize = cc.renderer.device.caps ? cc.renderer.device.caps.maxTextureSize : MAX_SIZE;
if (_canvasSize.width > maxTextureSize || _canvasSize.height > maxTextureSize) {
cc.warn("The maximum texture size supported by the device is " + maxTextureSize);
}
_canvasSize.width = Math.min(_canvasSize.width, maxTextureSize);
_canvasSize.height = Math.min(_canvasSize.height, maxTextureSize);
let recreate = false;
if (_canvas.width !== _canvasSize.width) {
_canvas.width = _canvasSize.width;
recreate = true
}
if (_canvas.height !== _canvasSize.height) {
_canvas.height = _canvasSize.height;
recreate = true
}
recreate && (_context.font = _fontDesc);
// align
_context.textAlign = Alignment[_hAlign];
}
_getFontDesc () {
let fontDesc = _fontSize.toString() + 'px ';
fontDesc = fontDesc + _fontFamily;
if (_enableBold) {
fontDesc = "bold " + fontDesc;
}
if (_enableItalic) {
fontDesc = "italic " + fontDesc;
}
return fontDesc;
}
_getLineHeight () {
let nodeSpacingY = _lineHeight;
if (nodeSpacingY === 0) {
nodeSpacingY = _fontSize;
} else {
nodeSpacingY = nodeSpacingY * _fontSize / _drawFontSize;
}
return nodeSpacingY | 0;
}
_calculateParagraphLength (paragraphedStrings, ctx) {
let paragraphLength = [];
for (let i = 0; i < paragraphedStrings.length; ++i) {
let width = textUtils.safeMeasureText(ctx, paragraphedStrings[i], _fontDesc);
paragraphLength.push(width);
}
return paragraphLength;
}
_measureText (ctx, fontDesc) {
return function (string) {
return textUtils.safeMeasureText(ctx, string, fontDesc);
};
}
_calculateShrinkFont (paragraphedStrings) {
let paragraphLength = this._calculateParagraphLength(paragraphedStrings, _context);
let i = 0;
let totalHeight = 0;
let maxLength = 0;
if (_isWrapText) {
let canvasWidthNoMargin = _nodeContentSize.width;
let canvasHeightNoMargin = _nodeContentSize.height;
if (canvasWidthNoMargin < 0 || canvasHeightNoMargin < 0) {
return;
}
totalHeight = canvasHeightNoMargin + 1;
let actualFontSize = _fontSize + 1;
let textFragment = "";
//let startShrinkFontSize = actualFontSize | 0;
let left = 0, right = actualFontSize | 0, mid = 0;
while (left < right) {
mid = (left + right + 1) >> 1;
if (mid <= 0) {
cc.logID(4003);
break;
}
_fontSize = mid;
_fontDesc = this._getFontDesc();
_context.font = _fontDesc;
let lineHeight = this._getLineHeight();
totalHeight = 0;
for (i = 0; i < paragraphedStrings.length; ++i) {
let allWidth = textUtils.safeMeasureText(_context, paragraphedStrings[i], _fontDesc);
textFragment = textUtils.fragmentText(paragraphedStrings[i],
allWidth,
canvasWidthNoMargin,
this._measureText(_context, _fontDesc));
totalHeight += textFragment.length * lineHeight;
}
if (totalHeight > canvasHeightNoMargin) {
right = mid - 1;
} else {
left = mid;
}
}
if (left === 0) {
cc.logID(4003);
} else {
_fontSize = left;
_fontDesc = this._getFontDesc();
_context.font = _fontDesc;
}
} else {
totalHeight = paragraphedStrings.length * this._getLineHeight();
for (i = 0; i < paragraphedStrings.length; ++i) {
if (maxLength < paragraphLength[i]) {
maxLength = paragraphLength[i];
}
}
let scaleX = (_canvasSize.width - _canvasPadding.width) / maxLength;
let scaleY = _canvasSize.height / totalHeight;
_fontSize = (_drawFontSize * Math.min(1, scaleX, scaleY)) | 0;
_fontDesc = this._getFontDesc();
_context.font = _fontDesc;
}
}
_calculateWrapText (paragraphedStrings) {
if (!_isWrapText) return;
_splitedStrings = [];
let canvasWidthNoMargin = _nodeContentSize.width;
for (let i = 0; i < paragraphedStrings.length; ++i) {
let allWidth = textUtils.safeMeasureText(_context, paragraphedStrings[i], _fontDesc);
let textFragment = textUtils.fragmentText(paragraphedStrings[i],
allWidth,
canvasWidthNoMargin,
this._measureText(_context, _fontDesc));
_splitedStrings = _splitedStrings.concat(textFragment);
}
}
_calculateLabelFont () {
let paragraphedStrings = _string.split('\n');
_splitedStrings = paragraphedStrings;
_fontDesc = this._getFontDesc();
_context.font = _fontDesc;
switch (_overflow) {
case Overflow.NONE: {
let canvasSizeX = 0;
let canvasSizeY = 0;
for (let i = 0; i < paragraphedStrings.length; ++i) {
let paraLength = textUtils.safeMeasureText(_context, paragraphedStrings[i], _fontDesc);
canvasSizeX = canvasSizeX > paraLength ? canvasSizeX : paraLength;
}
canvasSizeY = (_splitedStrings.length + textUtils.BASELINE_RATIO) * this._getLineHeight();
let rawWidth = parseFloat(canvasSizeX.toFixed(2));
let rawHeight = parseFloat(canvasSizeY.toFixed(2));
_canvasSize.width = rawWidth + _canvasPadding.width;
_canvasSize.height = rawHeight + _canvasPadding.height;
_nodeContentSize.width = rawWidth + _contentSizeExtend.width;
_nodeContentSize.height = rawHeight + _contentSizeExtend.height;
break;
}
case Overflow.SHRINK: {
this._calculateShrinkFont(paragraphedStrings);
this._calculateWrapText(paragraphedStrings);
break;
}
case Overflow.CLAMP: {
this._calculateWrapText(paragraphedStrings);
break;
}
case Overflow.RESIZE_HEIGHT: {
this._calculateWrapText(paragraphedStrings);
let rawHeight = (_splitedStrings.length + textUtils.BASELINE_RATIO) * this._getLineHeight();
_canvasSize.height = rawHeight + _canvasPadding.height;
// set node height
_nodeContentSize.height = rawHeight + _contentSizeExtend.height;
break;
}
}
}
}

View File

@@ -0,0 +1,53 @@
const dynamicAtlasManager = require('./dynamic-atlas/manager');
const WHITE = cc.Color.WHITE;
// share data of bmfont
let shareLabelInfo = {
fontAtlas: null,
fontSize:0,
lineHeight:0,
hAlign:0,
vAlign:0,
hash:"",
fontFamily:"",
fontDesc:"Arial",
color:WHITE,
isOutlined:false,
out:WHITE,
margin:0,
}
module.exports = {
deleteFromDynamicAtlas (comp, frame) {
if (frame && !CC_TEST) {
if (frame._original && dynamicAtlasManager) {
dynamicAtlasManager.deleteAtlasSpriteFrame(frame);
frame._resetDynamicAtlasFrame();
}
}
},
getFontFamily (comp) {
if (!comp.useSystemFont) {
if (comp.font) {
if (comp.font._nativeAsset) {
return comp.font._nativeAsset;
}
cc.assetManager.postLoadNative(comp.font, function (err) {
comp.isValid && comp.setVertsDirty();
});
return 'Arial';
}
return 'Arial';
}
else {
return comp.fontFamily || 'Arial';
}
},
shareLabelInfo: shareLabelInfo
}

View File

@@ -0,0 +1,669 @@
/****************************************************************************
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';
cc.Graphics.earcut = module.exports = earcut;
function earcut(data, holeIndices, dim) {
dim = dim || 2;
var hasHoles = holeIndices && holeIndices.length,
outerLen = hasHoles ? holeIndices[0] * dim : data.length,
outerNode = linkedList(data, 0, outerLen, dim, true),
triangles = [];
if (!outerNode) return triangles;
var minX, minY, maxX, maxY, x, y, size;
if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim);
// if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
if (data.length > 80 * dim) {
minX = maxX = data[0];
minY = maxY = data[1];
for (var i = dim; i < outerLen; i += dim) {
x = data[i];
y = data[i + 1];
if (x < minX) minX = x;
if (y < minY) minY = y;
if (x > maxX) maxX = x;
if (y > maxY) maxY = y;
}
// minX, minY and size are later used to transform coords into integers for z-order calculation
size = Math.max(maxX - minX, maxY - minY);
}
earcutLinked(outerNode, triangles, dim, minX, minY, size);
return triangles;
}
// create a circular doubly linked list from polygon points in the specified winding order
function linkedList(data, start, end, dim, clockwise) {
var i, last;
if (clockwise === (signedArea(data, start, end, dim) > 0)) {
for (i = start; i < end; i += dim) last = insertNode(i, data[i], data[i + 1], last);
} else {
for (i = end - dim; i >= start; i -= dim) last = insertNode(i, data[i], data[i + 1], last);
}
if (last && equals(last, last.next)) {
removeNode(last);
last = last.next;
}
return last;
}
// eliminate colinear or duplicate points
function filterPoints(start, end) {
if (!start) return start;
if (!end) end = start;
var p = start,
again;
do {
again = false;
if (!p.steiner && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) {
removeNode(p);
p = end = p.prev;
if (p === p.next) return null;
again = true;
} else {
p = p.next;
}
} while (again || p !== end);
return end;
}
// main ear slicing loop which triangulates a polygon (given as a linked list)
function earcutLinked(ear, triangles, dim, minX, minY, size, pass) {
if (!ear) return;
// interlink polygon nodes in z-order
if (!pass && size) indexCurve(ear, minX, minY, size);
var stop = ear,
prev, next;
// iterate through ears, slicing them one by one
while (ear.prev !== ear.next) {
prev = ear.prev;
next = ear.next;
if (size ? isEarHashed(ear, minX, minY, size) : isEar(ear)) {
// cut off the triangle
triangles.push(prev.i / dim);
triangles.push(ear.i / dim);
triangles.push(next.i / dim);
removeNode(ear);
// skipping the next vertice leads to less sliver triangles
ear = next.next;
stop = next.next;
continue;
}
ear = next;
// if we looped through the whole remaining polygon and can't find any more ears
if (ear === stop) {
// try filtering points and slicing again
if (!pass) {
earcutLinked(filterPoints(ear), triangles, dim, minX, minY, size, 1);
// if this didn't work, try curing all small self-intersections locally
} else if (pass === 1) {
ear = cureLocalIntersections(ear, triangles, dim);
earcutLinked(ear, triangles, dim, minX, minY, size, 2);
// as a last resort, try splitting the remaining polygon into two
} else if (pass === 2) {
splitEarcut(ear, triangles, dim, minX, minY, size);
}
break;
}
}
}
// check whether a polygon node forms a valid ear with adjacent nodes
function isEar(ear) {
var a = ear.prev,
b = ear,
c = ear.next;
if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
// now make sure we don't have other points inside the potential ear
var p = ear.next.next;
while (p !== ear.prev) {
if (pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
area(p.prev, p, p.next) >= 0) return false;
p = p.next;
}
return true;
}
function isEarHashed(ear, minX, minY, size) {
var a = ear.prev,
b = ear,
c = ear.next;
if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
// triangle bbox; min & max are calculated like this for speed
var minTX = a.x < b.x ? (a.x < c.x ? a.x : c.x) : (b.x < c.x ? b.x : c.x),
minTY = a.y < b.y ? (a.y < c.y ? a.y : c.y) : (b.y < c.y ? b.y : c.y),
maxTX = a.x > b.x ? (a.x > c.x ? a.x : c.x) : (b.x > c.x ? b.x : c.x),
maxTY = a.y > b.y ? (a.y > c.y ? a.y : c.y) : (b.y > c.y ? b.y : c.y);
// z-order range for the current triangle bbox;
var minZ = zOrder(minTX, minTY, minX, minY, size),
maxZ = zOrder(maxTX, maxTY, minX, minY, size);
// first look for points inside the triangle in increasing z-order
var p = ear.nextZ;
while (p && p.z <= maxZ) {
if (p !== ear.prev && p !== ear.next &&
pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
area(p.prev, p, p.next) >= 0) return false;
p = p.nextZ;
}
// then look for points in decreasing z-order
p = ear.prevZ;
while (p && p.z >= minZ) {
if (p !== ear.prev && p !== ear.next &&
pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
area(p.prev, p, p.next) >= 0) return false;
p = p.prevZ;
}
return true;
}
// go through all polygon nodes and cure small local self-intersections
function cureLocalIntersections(start, triangles, dim) {
var p = start;
do {
var a = p.prev,
b = p.next.next;
if (!equals(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) {
triangles.push(a.i / dim);
triangles.push(p.i / dim);
triangles.push(b.i / dim);
// remove two nodes involved
removeNode(p);
removeNode(p.next);
p = start = b;
}
p = p.next;
} while (p !== start);
return p;
}
// try splitting polygon into two and triangulate them independently
function splitEarcut(start, triangles, dim, minX, minY, size) {
// look for a valid diagonal that divides the polygon into two
var a = start;
do {
var b = a.next.next;
while (b !== a.prev) {
if (a.i !== b.i && isValidDiagonal(a, b)) {
// split the polygon in two by the diagonal
var c = splitPolygon(a, b);
// filter colinear points around the cuts
a = filterPoints(a, a.next);
c = filterPoints(c, c.next);
// run earcut on each half
earcutLinked(a, triangles, dim, minX, minY, size);
earcutLinked(c, triangles, dim, minX, minY, size);
return;
}
b = b.next;
}
a = a.next;
} while (a !== start);
}
// link every hole into the outer loop, producing a single-ring polygon without holes
function eliminateHoles(data, holeIndices, outerNode, dim) {
var queue = [],
i, len, start, end, list;
for (i = 0, len = holeIndices.length; i < len; i++) {
start = holeIndices[i] * dim;
end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
list = linkedList(data, start, end, dim, false);
if (list === list.next) list.steiner = true;
queue.push(getLeftmost(list));
}
queue.sort(compareX);
// process holes from left to right
for (i = 0; i < queue.length; i++) {
eliminateHole(queue[i], outerNode);
outerNode = filterPoints(outerNode, outerNode.next);
}
return outerNode;
}
function compareX(a, b) {
return a.x - b.x;
}
// find a bridge between vertices that connects hole with an outer ring and and link it
function eliminateHole(hole, outerNode) {
outerNode = findHoleBridge(hole, outerNode);
if (outerNode) {
var b = splitPolygon(outerNode, hole);
filterPoints(b, b.next);
}
}
// David Eberly's algorithm for finding a bridge between hole and outer polygon
function findHoleBridge(hole, outerNode) {
var p = outerNode,
hx = hole.x,
hy = hole.y,
qx = -Infinity,
m;
// find a segment intersected by a ray from the hole's leftmost point to the left;
// segment's endpoint with lesser x will be potential connection point
do {
if (hy <= p.y && hy >= p.next.y) {
var x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
if (x <= hx && x > qx) {
qx = x;
if (x === hx) {
if (hy === p.y) return p;
if (hy === p.next.y) return p.next;
}
m = p.x < p.next.x ? p : p.next;
}
}
p = p.next;
} while (p !== outerNode);
if (!m) return null;
if (hx === qx) return m.prev; // hole touches outer segment; pick lower endpoint
// look for points inside the triangle of hole point, segment intersection and endpoint;
// if there are no points found, we have a valid connection;
// otherwise choose the point of the minimum angle with the ray as connection point
var stop = m,
mx = m.x,
my = m.y,
tanMin = Infinity,
tan;
p = m.next;
while (p !== stop) {
if (hx >= p.x && p.x >= mx &&
pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {
tan = Math.abs(hy - p.y) / (hx - p.x); // tangential
if ((tan < tanMin || (tan === tanMin && p.x > m.x)) && locallyInside(p, hole)) {
m = p;
tanMin = tan;
}
}
p = p.next;
}
return m;
}
// interlink polygon nodes in z-order
function indexCurve(start, minX, minY, size) {
var p = start;
do {
if (p.z === null) p.z = zOrder(p.x, p.y, minX, minY, size);
p.prevZ = p.prev;
p.nextZ = p.next;
p = p.next;
} while (p !== start);
p.prevZ.nextZ = null;
p.prevZ = null;
sortLinked(p);
}
// Simon Tatham's linked list merge sort algorithm
// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
function sortLinked(list) {
var i, p, q, e, tail, numMerges, pSize, qSize,
inSize = 1;
do {
p = list;
list = null;
tail = null;
numMerges = 0;
while (p) {
numMerges++;
q = p;
pSize = 0;
for (i = 0; i < inSize; i++) {
pSize++;
q = q.nextZ;
if (!q) break;
}
qSize = inSize;
while (pSize > 0 || (qSize > 0 && q)) {
if (pSize === 0) {
e = q;
q = q.nextZ;
qSize--;
} else if (qSize === 0 || !q) {
e = p;
p = p.nextZ;
pSize--;
} else if (p.z <= q.z) {
e = p;
p = p.nextZ;
pSize--;
} else {
e = q;
q = q.nextZ;
qSize--;
}
if (tail) tail.nextZ = e;
else list = e;
e.prevZ = tail;
tail = e;
}
p = q;
}
tail.nextZ = null;
inSize *= 2;
} while (numMerges > 1);
return list;
}
// z-order of a point given coords and size of the data bounding box
function zOrder(x, y, minX, minY, size) {
// coords are transformed into non-negative 15-bit integer range
x = 32767 * (x - minX) / size;
y = 32767 * (y - minY) / size;
x = (x | (x << 8)) & 0x00FF00FF;
x = (x | (x << 4)) & 0x0F0F0F0F;
x = (x | (x << 2)) & 0x33333333;
x = (x | (x << 1)) & 0x55555555;
y = (y | (y << 8)) & 0x00FF00FF;
y = (y | (y << 4)) & 0x0F0F0F0F;
y = (y | (y << 2)) & 0x33333333;
y = (y | (y << 1)) & 0x55555555;
return x | (y << 1);
}
// find the leftmost node of a polygon ring
function getLeftmost(start) {
var p = start,
leftmost = start;
do {
if (p.x < leftmost.x) leftmost = p;
p = p.next;
} while (p !== start);
return leftmost;
}
// check if a point lies within a convex triangle
function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
return (cx - px) * (ay - py) - (ax - px) * (cy - py) >= 0 &&
(ax - px) * (by - py) - (bx - px) * (ay - py) >= 0 &&
(bx - px) * (cy - py) - (cx - px) * (by - py) >= 0;
}
// check if a diagonal between two polygon nodes is valid (lies in polygon interior)
function isValidDiagonal(a, b) {
return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) &&
locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b);
}
// signed area of a triangle
function area(p, q, r) {
return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
}
// check if two points are equal
function equals(p1, p2) {
return p1.x === p2.x && p1.y === p2.y;
}
// check if two segments intersect
function intersects(p1, q1, p2, q2) {
if ((equals(p1, q1) && equals(p2, q2)) ||
(equals(p1, q2) && equals(p2, q1))) return true;
return area(p1, q1, p2) > 0 !== area(p1, q1, q2) > 0 &&
area(p2, q2, p1) > 0 !== area(p2, q2, q1) > 0;
}
// check if a polygon diagonal intersects any polygon segments
function intersectsPolygon(a, b) {
var p = a;
do {
if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&
intersects(p, p.next, a, b)) return true;
p = p.next;
} while (p !== a);
return false;
}
// check if a polygon diagonal is locally inside the polygon
function locallyInside(a, b) {
return area(a.prev, a, a.next) < 0 ?
area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 :
area(a, b, a.prev) < 0 || area(a, a.next, b) < 0;
}
// check if the middle point of a polygon diagonal is inside the polygon
function middleInside(a, b) {
var p = a,
inside = false,
px = (a.x + b.x) / 2,
py = (a.y + b.y) / 2;
do {
if (((p.y > py) !== (p.next.y > py)) && (px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x))
inside = !inside;
p = p.next;
} while (p !== a);
return inside;
}
// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
// if one belongs to the outer ring and another to a hole, it merges it into a single ring
function splitPolygon(a, b) {
var a2 = new Node(a.i, a.x, a.y),
b2 = new Node(b.i, b.x, b.y),
an = a.next,
bp = b.prev;
a.next = b;
b.prev = a;
a2.next = an;
an.prev = a2;
b2.next = a2;
a2.prev = b2;
bp.next = b2;
b2.prev = bp;
return b2;
}
// create a node and optionally link it with previous one (in a circular doubly linked list)
function insertNode(i, x, y, last) {
var p = new Node(i, x, y);
if (!last) {
p.prev = p;
p.next = p;
} else {
p.next = last.next;
p.prev = last;
last.next.prev = p;
last.next = p;
}
return p;
}
function removeNode(p) {
p.next.prev = p.prev;
p.prev.next = p.next;
if (p.prevZ) p.prevZ.nextZ = p.nextZ;
if (p.nextZ) p.nextZ.prevZ = p.prevZ;
}
function Node(i, x, y) {
// vertice index in coordinates array
this.i = i;
// vertex coordinates
this.x = x;
this.y = y;
// previous and next vertice nodes in a polygon ring
this.prev = null;
this.next = null;
// z-order curve value
this.z = null;
// previous and next nodes in z-order
this.prevZ = null;
this.nextZ = null;
// indicates whether this is a steiner point
this.steiner = false;
}
// return a percentage difference between the polygon area and its triangulation area;
// used to verify correctness of triangulation
earcut.deviation = function (data, holeIndices, dim, triangles) {
var hasHoles = holeIndices && holeIndices.length;
var outerLen = hasHoles ? holeIndices[0] * dim : data.length;
var polygonArea = Math.abs(signedArea(data, 0, outerLen, dim));
if (hasHoles) {
for (var i = 0, len = holeIndices.length; i < len; i++) {
var start = holeIndices[i] * dim;
var end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
polygonArea -= Math.abs(signedArea(data, start, end, dim));
}
}
var trianglesArea = 0;
for (i = 0; i < triangles.length; i += 3) {
var a = triangles[i] * dim;
var b = triangles[i + 1] * dim;
var c = triangles[i + 2] * dim;
trianglesArea += Math.abs(
(data[a] - data[c]) * (data[b + 1] - data[a + 1]) -
(data[a] - data[b]) * (data[c + 1] - data[a + 1]));
}
return polygonArea === 0 && trianglesArea === 0 ? 0 :
Math.abs((trianglesArea - polygonArea) / polygonArea);
};
function signedArea(data, start, end, dim) {
var sum = 0;
for (var i = start, j = end - dim; i < end; i += dim) {
sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
j = i;
}
return sum;
}
// turn a polygon in a multi-dimensional array form (e.g. as in GeoJSON) into a form Earcut accepts
earcut.flatten = function (data) {
var dim = data[0][0].length,
result = {vertices: [], holes: [], dimensions: dim},
holeIndex = 0;
for (var i = 0; i < data.length; i++) {
for (var j = 0; j < data[i].length; j++) {
for (var d = 0; d < dim; d++) result.vertices.push(data[i][j][d]);
}
if (i > 0) {
holeIndex += data[i - 1].length;
result.holes.push(holeIndex);
}
}
return result;
};

View File

@@ -0,0 +1,217 @@
/****************************************************************************
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 Helper = require('../../../../graphics/helper');
const PointFlags = require('../../../../graphics/types').PointFlags;
let Point = cc.Graphics.Point = cc.Class({
name: 'cc.GraphicsPoint',
extends: cc.Vec2,
ctor (x, y) {
this.reset();
},
reset () {
this.dx = 0;
this.dy = 0;
this.dmx = 0;
this.dmy = 0;
this.flags = 0;
this.len = 0;
}
});
function Path () {
this.reset();
}
cc.js.mixin(Path.prototype, {
reset () {
this.closed = false;
this.nbevel = 0;
this.complex = true;
if (this.points) {
this.points.length = 0;
}
else {
this.points = [];
}
}
});
function Impl (graphics) {
// inner properties
this._tessTol = 0.25;
this._distTol = 0.01;
this._updatePathOffset = false;
this._paths = null;
this._pathLength = 0;
this._pathOffset = 0;
this._points = null;
this._pointsOffset = 0;
this._commandx = 0;
this._commandy = 0;
this._paths = [];
this._points = [];
}
cc.js.mixin(Impl.prototype, {
moveTo (x, y) {
if (this._updatePathOffset) {
this._pathOffset = this._pathLength;
this._updatePathOffset = false;
}
this._addPath();
this._addPoint(x, y, PointFlags.PT_CORNER);
this._commandx = x;
this._commandy = y;
},
lineTo (x, y) {
this._addPoint(x, y, PointFlags.PT_CORNER);
this._commandx = x;
this._commandy = y;
},
bezierCurveTo (c1x, c1y, c2x, c2y, x, y) {
var path = this._curPath;
var last = path.points[path.points.length - 1];
if (last.x === c1x && last.y === c1y && c2x === x && c2y === y) {
this.lineTo(x, y);
return;
}
Helper.tesselateBezier(this, last.x, last.y, c1x, c1y, c2x, c2y, x, y, 0, PointFlags.PT_CORNER);
this._commandx = x;
this._commandy = y;
},
quadraticCurveTo (cx, cy, x, y) {
var x0 = this._commandx;
var y0 = this._commandy;
this.bezierCurveTo(x0 + 2.0 / 3.0 * (cx - x0), y0 + 2.0 / 3.0 * (cy - y0), x + 2.0 / 3.0 * (cx - x), y + 2.0 / 3.0 * (cy - y), x, y);
},
arc (cx, cy, r, startAngle, endAngle, counterclockwise) {
Helper.arc(this, cx, cy, r, startAngle, endAngle, counterclockwise);
},
ellipse (cx, cy, rx, ry) {
Helper.ellipse(this, cx, cy, rx, ry);
this._curPath.complex = false;
},
circle (cx, cy, r) {
Helper.ellipse(this, cx, cy, r, r);
this._curPath.complex = false;
},
rect (x, y, w, h) {
this.moveTo(x, y);
this.lineTo(x, y + h);
this.lineTo(x + w, y + h);
this.lineTo(x + w, y);
this.close();
this._curPath.complex = false;
},
roundRect (x, y, w, h, r) {
Helper.roundRect(this, x, y, w, h, r);
this._curPath.complex = false;
},
clear (clean) {
this._pathLength = 0;
this._pathOffset = 0;
this._pointsOffset = 0;
this._curPath = null;
if (clean) {
this._paths.length = 0;
this._points.length = 0;
}
},
close () {
this._curPath.closed = true;
},
_addPath () {
var offset = this._pathLength;
var path = this._paths[offset];
if (!path) {
path = new Path();
this._paths.push(path);
} else {
path.reset();
}
this._pathLength++;
this._curPath = path;
return path;
},
_addPoint (x, y, flags) {
var path = this._curPath;
if (!path) return;
var pt;
var points = this._points;
var pathPoints = path.points;
var offset = this._pointsOffset++;
pt = points[offset];
if (!pt) {
pt = new Point(x, y);
points.push(pt);
} else {
pt.x = x;
pt.y = y;
}
pt.flags = flags;
pathPoints.push(pt);
},
});
cc.Graphics._Impl = Impl;
module.exports = Impl;

View File

@@ -0,0 +1,703 @@
/****************************************************************************
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 '../../../assembler';
import InputAssembler from '../../../../../renderer/core/input-assembler';
const MeshBuffer = require('../../mesh-buffer');
const renderer = require('../../../index');
const Graphics = require('../../../../graphics/graphics');
const PointFlags = require('../../../../graphics/types').PointFlags;
const LineJoin = Graphics.LineJoin;
const LineCap = Graphics.LineCap;
const Earcut = require('./earcut');
require('./impl');
const MAX_VERTEX = 65535;
const MAX_INDICE = MAX_VERTEX * 2;
const PI = Math.PI;
const min = Math.min;
const max = Math.max;
const ceil = Math.ceil;
const acos = Math.acos;
const cos = Math.cos;
const sin = Math.sin;
const atan2 = Math.atan2;
function curveDivs (r, arc, tol) {
let da = acos(r / (r + tol)) * 2.0;
return max(2, ceil(arc / da));
}
function clamp (v, min, max) {
if (v < min) {
return min;
}
else if (v > max) {
return max;
}
return v;
}
let gfx = cc.gfx;
let vfmtPosColorSdf = new gfx.VertexFormat([
{ name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
{ name: gfx.ATTR_COLOR, type: gfx.ATTR_TYPE_UINT8, num: 4, normalize: true },
{ name: 'a_dist', type: gfx.ATTR_TYPE_FLOAT32, num: 1 },
]);
vfmtPosColorSdf.name = 'vfmtPosColorSdf';
export default class GraphicsAssembler extends Assembler {
constructor (graphics) {
super(graphics);
this._buffer = null;
this._buffers = [];
this._bufferOffset = 0;
}
getVfmt () {
return vfmtPosColorSdf;
}
getVfmtFloatCount () {
return 4;
}
requestBuffer () {
let buffer = {
indiceStart: 0,
vertexStart: 0
};
let meshbuffer = new MeshBuffer(renderer._handle, this.getVfmt());
buffer.meshbuffer = meshbuffer;
let ia = new InputAssembler(meshbuffer._vb, meshbuffer._ib);
buffer.ia = ia;
this._buffers.push(buffer);
return buffer;
}
getBuffers () {
if (this._buffers.length === 0) {
this.requestBuffer();
}
return this._buffers;
}
clear (clean) {
this._bufferOffset = 0;
let datas = this._buffers;
if (clean) {
for (let i = 0, l = datas.length; i < l; i++) {
let data = datas[i];
data.meshbuffer.destroy();
data.meshbuffer = null;
}
datas.length = 0;
}
else {
for (let i = 0, l = datas.length; i < l; i++) {
let data = datas[i];
data.indiceStart = 0;
data.vertexStart = 0;
let meshbuffer = data.meshbuffer;
meshbuffer.reset();
}
}
}
fillBuffers (graphics, renderer) {
renderer._flush();
renderer.node = graphics.node;
renderer.material = graphics._materials[0];
let buffers = this.getBuffers();
for (let index = 0, length = buffers.length; index < length; index++) {
let buffer = buffers[index];
let meshbuffer = buffer.meshbuffer;
buffer.ia._count = buffer.indiceStart;
renderer._flushIA(buffer.ia);
meshbuffer.uploadData();
}
}
genBuffer (graphics, cverts) {
let buffers = this.getBuffers();
let buffer = buffers[this._bufferOffset];
let meshbuffer = buffer.meshbuffer;
let maxVertsCount = buffer.vertexStart + cverts;
if (maxVertsCount > MAX_VERTEX ||
maxVertsCount * 3 > MAX_INDICE) {
++this._bufferOffset;
maxVertsCount = cverts;
if (this._bufferOffset < buffers.length) {
buffer = buffers[this._bufferOffset];
}
else {
buffer = this.requestBuffer(graphics);
buffers[this._bufferOffset] = buffer;
}
meshbuffer = buffer.meshbuffer;
}
if (maxVertsCount > meshbuffer.vertexOffset) {
meshbuffer.requestStatic(cverts, cverts*3);
}
this._buffer = buffer;
return buffer;
}
stroke (graphics) {
this._curColor = graphics._strokeColor._val;
this._flattenPaths(graphics._impl);
this._expandStroke(graphics);
graphics._impl._updatePathOffset = true;
}
fill (graphics) {
this._curColor = graphics._fillColor._val;
this._expandFill(graphics);
graphics._impl._updatePathOffset = true;
}
_expandStroke (graphics) {
let w = graphics.lineWidth * 0.5,
lineCap = graphics.lineCap,
lineJoin = graphics.lineJoin,
miterLimit = graphics.miterLimit;
let impl = graphics._impl;
let ncap = curveDivs(w, PI, impl._tessTol);
this._calculateJoins(impl, w, lineJoin, miterLimit);
let paths = impl._paths;
// Calculate max vertex usage.
let cverts = 0;
for (let i = impl._pathOffset, l = impl._pathLength; i < l; i++) {
let path = paths[i];
let pointsLength = path.points.length;
if (lineJoin === LineJoin.ROUND) cverts += (pointsLength + path.nbevel * (ncap + 2) + 1) * 2; // plus one for loop
else cverts += (pointsLength + path.nbevel * 5 + 1) * 2; // plus one for loop
if (!path.closed) {
// space for caps
if (lineCap === LineCap.ROUND) {
cverts += (ncap * 2 + 2) * 2;
} else {
cverts += (3 + 3) * 2;
}
}
}
let buffer = this.genBuffer(graphics, cverts),
meshbuffer = buffer.meshbuffer,
vData = meshbuffer._vData,
iData = meshbuffer._iData;
for (let i = impl._pathOffset, l = impl._pathLength; i < l; i++) {
let path = paths[i];
let pts = path.points;
let pointsLength = pts.length;
let offset = buffer.vertexStart;
let p0, p1;
let start, end, loop;
loop = path.closed;
if (loop) {
// Looping
p0 = pts[pointsLength - 1];
p1 = pts[0];
start = 0;
end = pointsLength;
} else {
// Add cap
p0 = pts[0];
p1 = pts[1];
start = 1;
end = pointsLength - 1;
}
p1 = p1 || p0;
if (!loop) {
// Add cap
let dPos = p1.sub(p0);
dPos.normalizeSelf();
let dx = dPos.x;
let dy = dPos.y;
if (lineCap === LineCap.BUTT)
this._buttCapStart(p0, dx, dy, w, 0);
else if (lineCap === LineCap.SQUARE)
this._buttCapStart(p0, dx, dy, w, w);
else if (lineCap === LineCap.ROUND)
this._roundCapStart(p0, dx, dy, w, ncap);
}
for (let j = start; j < end; ++j) {
if (lineJoin === LineJoin.ROUND) {
this._roundJoin(p0, p1, w, w, ncap);
}
else if ((p1.flags & (PointFlags.PT_BEVEL | PointFlags.PT_INNERBEVEL)) !== 0) {
this._bevelJoin(p0, p1, w, w);
}
else {
this._vset(p1.x + p1.dmx * w, p1.y + p1.dmy * w, 1);
this._vset(p1.x - p1.dmx * w, p1.y - p1.dmy * w, -1);
}
p0 = p1;
p1 = pts[j + 1];
}
if (loop) {
// Loop it
let floatCount = this.getVfmtFloatCount();
let vDataoOfset = offset * floatCount;
this._vset(vData[vDataoOfset], vData[vDataoOfset+1], 1);
this._vset(vData[vDataoOfset+floatCount], vData[vDataoOfset+floatCount+1], -1);
} else {
// Add cap
let dPos = p1.sub(p0);
dPos.normalizeSelf();
let dx = dPos.x;
let dy = dPos.y;
if (lineCap === LineCap.BUTT)
this._buttCapEnd(p1, dx, dy, w, 0);
else if (lineCap === LineCap.SQUARE)
this._buttCapEnd(p1, dx, dy, w, w);
else if (lineCap === LineCap.ROUND)
this._roundCapEnd(p1, dx, dy, w, ncap);
}
// stroke indices
let indicesOffset = buffer.indiceStart;
for (let start = offset+2, end = buffer.vertexStart; start < end; start++) {
iData[indicesOffset++] = start - 2;
iData[indicesOffset++] = start - 1;
iData[indicesOffset++] = start;
}
buffer.indiceStart = indicesOffset;
}
}
_expandFill (graphics) {
let impl = graphics._impl;
let paths = impl._paths;
// Calculate max vertex usage.
let cverts = 0;
for (let i = impl._pathOffset, l = impl._pathLength; i < l; i++) {
let path = paths[i];
let pointsLength = path.points.length;
cverts += pointsLength;
}
let buffer = this.genBuffer(graphics, cverts),
meshbuffer = buffer.meshbuffer,
vData = meshbuffer._vData,
iData = meshbuffer._iData;
for (let i = impl._pathOffset, l = impl._pathLength; i < l; i++) {
let path = paths[i];
let pts = path.points;
let pointsLength = pts.length;
if (pointsLength === 0) {
continue;
}
// Calculate shape vertices.
let offset = buffer.vertexStart;
for (let j = 0; j < pointsLength; ++j) {
this._vset(pts[j].x, pts[j].y);
}
let indicesOffset = buffer.indiceStart;
if (path.complex) {
let earcutData = [];
let floatCount = this.getVfmtFloatCount();
for (let j = offset, end = buffer.vertexStart; j < end; j++) {
let vDataOffset = j * floatCount;
earcutData.push(vData[vDataOffset]);
earcutData.push(vData[vDataOffset+1]);
}
let newIndices = Earcut(earcutData, null, 2);
if (!newIndices || newIndices.length === 0) {
continue;
}
for (let j = 0, nIndices = newIndices.length; j < nIndices; j++) {
iData[indicesOffset++] = newIndices[j] + offset;
}
}
else {
let first = offset;
for (let start = offset+2, end = buffer.vertexStart; start < end; start++) {
iData[indicesOffset++] = first;
iData[indicesOffset++] = start - 1;
iData[indicesOffset++] = start;
}
}
buffer.indiceStart = indicesOffset;
}
}
_calculateJoins (impl, w, lineJoin, miterLimit) {
let iw = 0.0;
let w2 = w * w;
if (w > 0.0) {
iw = 1 / w;
}
// Calculate which joins needs extra vertices to append, and gather vertex count.
let paths = impl._paths;
for (let i = impl._pathOffset, l = impl._pathLength; i < l; i++) {
let path = paths[i];
let pts = path.points;
let ptsLength = pts.length;
let p0 = pts[ptsLength - 1];
let p1 = pts[0];
let nleft = 0;
path.nbevel = 0;
for (let j = 0; j < ptsLength; j++) {
let dmr2, cross, limit;
// perp normals
let dlx0 = p0.dy;
let dly0 = -p0.dx;
let dlx1 = p1.dy;
let dly1 = -p1.dx;
// Calculate extrusions
p1.dmx = (dlx0 + dlx1) * 0.5;
p1.dmy = (dly0 + dly1) * 0.5;
dmr2 = p1.dmx * p1.dmx + p1.dmy * p1.dmy;
if (dmr2 > 0.000001) {
let scale = 1 / dmr2;
if (scale > 600) {
scale = 600;
}
p1.dmx *= scale;
p1.dmy *= scale;
}
// Keep track of left turns.
cross = p1.dx * p0.dy - p0.dx * p1.dy;
if (cross > 0) {
nleft++;
p1.flags |= PointFlags.PT_LEFT;
}
// Calculate if we should use bevel or miter for inner join.
limit = max(11, min(p0.len, p1.len) * iw);
if (dmr2 * limit * limit < 1) {
p1.flags |= PointFlags.PT_INNERBEVEL;
}
// Check whether dm length is too long
let dmwx = p1.dmx * w;
let dmwy = p1.dmy * w;
let dmlen2 = dmwx*dmwx + dmwy*dmwy;
if (dmlen2 > (p1.len * p1.len) + w2 && dmlen2 > (p0.len * p0.len) + w2) {
p1.flags |= PointFlags.PT_INNERBEVEL;
}
// Check to see if the corner needs to be beveled.
if (p1.flags & PointFlags.PT_CORNER) {
if (dmr2 * miterLimit * miterLimit < 1 || lineJoin === LineJoin.BEVEL || lineJoin === LineJoin.ROUND) {
p1.flags |= PointFlags.PT_BEVEL;
}
}
if ((p1.flags & (PointFlags.PT_BEVEL | PointFlags.PT_INNERBEVEL)) !== 0) {
path.nbevel++;
}
p0 = p1;
p1 = pts[j + 1];
}
}
}
_flattenPaths (impl) {
let paths = impl._paths;
for (let i = impl._pathOffset, l = impl._pathLength; i < l; i++) {
let path = paths[i];
let pts = path.points;
let p0 = pts[pts.length - 1];
let p1 = pts[0];
if (pts.length > 2 && p0.equals(p1)) {
path.closed = true;
pts.pop();
p0 = pts[pts.length - 1];
}
for (let j = 0, size = pts.length; j < size; j++) {
// Calculate segment direction and length
let dPos = p1.sub(p0);
p0.len = dPos.mag();
if (dPos.x || dPos.y)
dPos.normalizeSelf();
p0.dx = dPos.x;
p0.dy = dPos.y;
// Advance
p0 = p1;
p1 = pts[j + 1];
}
}
}
_chooseBevel (bevel, p0, p1, w) {
let x = p1.x;
let y = p1.y;
let x0, y0, x1, y1;
if (bevel !== 0) {
x0 = x + p0.dy * w;
y0 = y - p0.dx * w;
x1 = x + p1.dy * w;
y1 = y - p1.dx * w;
} else {
x0 = x1 = x + p1.dmx * w;
y0 = y1 = y + p1.dmy * w;
}
return [x0, y0, x1, y1];
}
_buttCapStart (p, dx, dy, w, d) {
let px = p.x - dx * d;
let py = p.y - dy * d;
let dlx = dy;
let dly = -dx;
this._vset(px + dlx * w, py + dly * w, 1);
this._vset(px - dlx * w, py - dly * w, -1);
}
_buttCapEnd (p, dx, dy, w, d) {
let px = p.x + dx * d;
let py = p.y + dy * d;
let dlx = dy;
let dly = -dx;
this._vset(px + dlx * w, py + dly * w, 1);
this._vset(px - dlx * w, py - dly * w, -1);
}
_roundCapStart (p, dx, dy, w, ncap) {
let px = p.x;
let py = p.y;
let dlx = dy;
let dly = -dx;
for (let i = 0; i < ncap; i++) {
let a = i / (ncap - 1) * PI;
let ax = cos(a) * w,
ay = sin(a) * w;
this._vset(px - dlx * ax - dx * ay, py - dly * ax - dy * ay, 1);
this._vset(px, py, 0);
}
this._vset(px + dlx * w, py + dly * w, 1);
this._vset(px - dlx * w, py - dly * w, -1);
}
_roundCapEnd (p, dx, dy, w, ncap) {
let px = p.x;
let py = p.y;
let dlx = dy;
let dly = -dx;
this._vset(px + dlx * w, py + dly * w, 1);
this._vset(px - dlx * w, py - dly * w, -1);
for (let i = 0; i < ncap; i++) {
let a = i / (ncap - 1) * PI;
let ax = cos(a) * w,
ay = sin(a) * w;
this._vset(px, py, 0);
this._vset(px - dlx * ax + dx * ay, py - dly * ax + dy * ay, 1);
}
}
_roundJoin (p0, p1, lw, rw, ncap) {
let dlx0 = p0.dy;
let dly0 = -p0.dx;
let dlx1 = p1.dy;
let dly1 = -p1.dx;
let p1x = p1.x;
let p1y = p1.y;
if ((p1.flags & PointFlags.PT_LEFT) !== 0) {
let out = this._chooseBevel(p1.flags & PointFlags.PT_INNERBEVEL, p0, p1, lw);
let lx0 = out[0];
let ly0 = out[1];
let lx1 = out[2];
let ly1 = out[3];
let a0 = atan2(-dly0, -dlx0);
let a1 = atan2(-dly1, -dlx1);
if (a1 > a0) a1 -= PI * 2;
this._vset(lx0, ly0, 1);
this._vset(p1x - dlx0 * rw, p1.y - dly0 * rw, -1);
let n = clamp(ceil((a0 - a1) / PI) * ncap, 2, ncap);
for (let i = 0; i < n; i++) {
let u = i / (n - 1);
let a = a0 + u * (a1 - a0);
let rx = p1x + cos(a) * rw;
let ry = p1y + sin(a) * rw;
this._vset(p1x, p1y, 0);
this._vset(rx, ry, -1);
}
this._vset(lx1, ly1, 1);
this._vset(p1x - dlx1 * rw, p1y - dly1 * rw, -1);
} else {
let out = this._chooseBevel(p1.flags & PointFlags.PT_INNERBEVEL, p0, p1, -rw);
let rx0 = out[0];
let ry0 = out[1];
let rx1 = out[2];
let ry1 = out[3];
let a0 = atan2(dly0, dlx0);
let a1 = atan2(dly1, dlx1);
if (a1 < a0) a1 += PI * 2;
this._vset(p1x + dlx0 * rw, p1y + dly0 * rw, 1);
this._vset(rx0, ry0, -1);
let n = clamp(ceil((a1 - a0) / PI) * ncap, 2, ncap);
for (let i = 0; i < n; i++) {
let u = i / (n - 1);
let a = a0 + u * (a1 - a0);
let lx = p1x + cos(a) * lw;
let ly = p1y + sin(a) * lw;
this._vset(lx, ly, 1);
this._vset(p1x, p1y, 0);
}
this._vset(p1x + dlx1 * rw, p1y + dly1 * rw, 1);
this._vset(rx1, ry1, -1);
}
}
_bevelJoin (p0, p1, lw, rw) {
let rx0, ry0, rx1, ry1;
let lx0, ly0, lx1, ly1;
let dlx0 = p0.dy;
let dly0 = -p0.dx;
let dlx1 = p1.dy;
let dly1 = -p1.dx;
if (p1.flags & PointFlags.PT_LEFT) {
let out = this._chooseBevel(p1.flags & PointFlags.PT_INNERBEVEL, p0, p1, lw);
lx0 = out[0];
ly0 = out[1];
lx1 = out[2];
ly1 = out[3];
this._vset(lx0, ly0, 1);
this._vset(p1.x - dlx0 * rw, p1.y - dly0 * rw, -1);
this._vset(lx1, ly1, 1);
this._vset(p1.x - dlx1 * rw, p1.y - dly1 * rw, -1);
} else {
let out = this._chooseBevel(p1.flags & PointFlags.PT_INNERBEVEL, p0, p1, -rw);
rx0 = out[0];
ry0 = out[1];
rx1 = out[2];
ry1 = out[3];
this._vset(p1.x + dlx0 * lw, p1.y + dly0 * lw, 1);
this._vset(rx0, ry0, -1);
this._vset(p1.x + dlx1 * lw, p1.y + dly1 * lw, 1);
this._vset(rx1, ry1, -1);
}
}
_vset (x, y, distance = 0) {
let buffer = this._buffer;
let meshbuffer = buffer.meshbuffer;
let dataOffset = buffer.vertexStart * this.getVfmtFloatCount();
let vData = meshbuffer._vData;
let uintVData = meshbuffer._uintVData;
vData[dataOffset] = x;
vData[dataOffset+1] = y;
uintVData[dataOffset+2] = this._curColor;
vData[dataOffset+3] = distance;
buffer.vertexStart ++;
meshbuffer._dirty = true;
}
}
Assembler.register(cc.Graphics, GraphicsAssembler);

View File

@@ -0,0 +1,32 @@
/****************************************************************************
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.
****************************************************************************/
cc.assemblers = {};
require('./sprite');
require('./mask-assembler');
require('./graphics');
require('./label');
require('./motion-streak');

View File

@@ -0,0 +1,180 @@
/****************************************************************************
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 BmfontAssembler from '../../../../utils/label/bmfont';
let _dataOffset = 0;
export default class WebglBmfontAssembler extends BmfontAssembler {
initData () {
this._renderData.createFlexData(0, 4, 6, this.getVfmt());
}
_reserveQuads (comp, count) {
let verticesCount = count * 4;
let indicesCount = count * 6;
let flexBuffer = this._renderData._flexBuffer;
flexBuffer.reserve(verticesCount, indicesCount);
flexBuffer.used(verticesCount, indicesCount);
let iData = this._renderData.iDatas[0];
for (let i = 0, vid = 0, l = indicesCount; i < l; i += 6, vid += 4) {
iData[i] = vid;
iData[i + 1] = vid + 1;
iData[i + 2] = vid + 2;
iData[i + 3] = vid + 1;
iData[i + 4] = vid + 3;
iData[i + 5] = vid + 2;
}
_dataOffset = 0;
}
_quadsUpdated (comp) {
_dataOffset = 0;
let flexBuffer = this._renderData._flexBuffer;
flexBuffer.used(this.verticesCount, this.indicesCount);
}
_getColor (comp) {
return comp.node._color._val;
}
appendQuad (comp, texture, rect, rotated, x, y, scale) {
let renderData = this._renderData;
let verts = renderData.vDatas[0],
uintVerts = renderData.uintVDatas[0];
this.verticesCount += 4;
this.indicesCount = this.verticesCount / 2 * 3;
let texw = texture.width,
texh = texture.height,
rectWidth = rect.width,
rectHeight = rect.height,
color = this._getColor(comp);
let l, b, r, t;
let floatsPerVert = this.floatsPerVert;
// uvs
let uvDataOffset = _dataOffset + this.uvOffset;
if (!rotated) {
l = (rect.x) / texw;
r = (rect.x + rectWidth) / texw;
b = (rect.y + rectHeight) / texh;
t = (rect.y) / texh;
verts[uvDataOffset] = l;
verts[uvDataOffset + 1] = b;
uvDataOffset += floatsPerVert;
verts[uvDataOffset] = r;
verts[uvDataOffset + 1] = b;
uvDataOffset += floatsPerVert;
verts[uvDataOffset] = l;
verts[uvDataOffset + 1] = t;
uvDataOffset += floatsPerVert;
verts[uvDataOffset] = r;
verts[uvDataOffset + 1] = t;
} else {
l = (rect.x) / texw;
r = (rect.x + rectHeight) / texw;
b = (rect.y + rectWidth) / texh;
t = (rect.y) / texh;
verts[uvDataOffset] = l;
verts[uvDataOffset + 1] = t;
uvDataOffset += floatsPerVert;
verts[uvDataOffset] = l;
verts[uvDataOffset + 1] = b;
uvDataOffset += floatsPerVert;
verts[uvDataOffset] = r;
verts[uvDataOffset + 1] = t;
uvDataOffset += floatsPerVert;
verts[uvDataOffset] = r;
verts[uvDataOffset + 1] = b;
}
// positions
l = x;
r = x + rectWidth * scale;
b = y - rectHeight * scale;
t = y;
this.appendVerts(comp, _dataOffset, l, r, b, t);
// colors
let colorOffset = _dataOffset + this.colorOffset;
for (let i = 0; i < 4; i++) {
uintVerts[colorOffset] = color;
colorOffset += floatsPerVert;
}
_dataOffset += this.floatsPerVert * 4;
}
appendVerts (comp, offset, l, r, b, t) {
let local = this._local;
let floatsPerVert = this.floatsPerVert;
local[offset] = l;
local[offset + 1] = b;
offset += floatsPerVert;
local[offset] = r;
local[offset + 1] = b;
offset += floatsPerVert;
local[offset] = l;
local[offset + 1] = t;
offset += floatsPerVert;
local[offset] = r;
local[offset + 1] = t;
}
updateWorldVerts (comp) {
let node = comp.node;
let matrix = 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 local = this._local;
let world = this._renderData.vDatas[0];
let floatsPerVert = this.floatsPerVert;
for (let offset = 0; offset < local.length; offset += floatsPerVert) {
let x = local[offset];
let y = local[offset + 1];
world[offset] = x * a + y * c + tx;
world[offset+1] = x * b + y * d + ty;
}
}
}

View File

@@ -0,0 +1,47 @@
/****************************************************************************
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 js = require('../../../../../platform/js');
const WebglBmfontAssembler = require('./bmfont');
const LetterFontAssembler = require('../../../../utils/label/letter-font');
const WHITE = cc.color(255, 255, 255, 255);
export default class WebglLetterFontAssembler extends LetterFontAssembler {
createData (comp) {
return comp.requestRenderData();
}
_getColor (comp) {
WHITE._fastSetA(comp.node._color.a);
return WHITE._val;
}
updateColor (comp) {
let color = this._getColor(comp);
super.updateColor(comp, color);
}
}

View File

@@ -0,0 +1,384 @@
import MaterialVariant from '../../../../../assets/material/material-variant';
const Label = require('../../../../../components/CCLabel');
const LabelShadow = require('../../../../../components/CCLabelShadow');
const LabelOutline = require('../../../../../components/CCLabelOutline');
const Material = require('../../../../../assets/material/CCMaterial');
const UPDATE_CONTENT = 1 << 0;
const UPDATE_FONT = 1 << 1;
const UPDATE_EFFECT = 1 << 2;
export default class NativeTTF {
init(comp) {
this.labelMaterial = null;
this._label = this._renderComp = comp;
renderer.CustomAssembler.prototype.ctor.call(this);
comp.node._proxy.setAssembler(this);
this._layout = new jsb.LabelRenderer();
this._layout.init(comp);
this._cfg = new DataView(this._layout._cfg);
this._layoutInfo = new DataView(this._layout._layout);
this._cfgFields = jsb.LabelRenderer._cfgFields;
this._layoutFields = jsb.LabelRenderer._layoutFields;
this._layout.bindNodeProxy(comp.node._proxy);
this._bindMaterial(comp);
}
_setBufferFlag(dv, offset, size, type, flag){
if ( type == "int8" && size == 1) {
let v = dv.getInt8(offset);
dv.setInt8(offset, flag | v);
} else if(type == "int32" && size == 4) {
let v = dv.getInt32(offset, jsb.__isLittleEndian__);
dv.setInt32(offset, flag|v , jsb.__isLittleEndian__);
} else {
cc.warn("flag storage type should be int8/int32 only, type/size -> " + type+"/"+size + ".");
}
}
_updateCfgFlag(flag) {
let field = this._cfgFields.updateFlags;
this._setBufferFlag(this._cfg, field.offset, field.size, field.type, flag);
}
_setBufferValue(dv, offset, size, type, value) {
if(type == "float" && size == 4) {
dv.setFloat32(offset, value, jsb.__isLittleEndian__);
} else if(type == "int32" && size == 4) {
dv.setInt32(offset, value, jsb.__isLittleEndian__);
} else if (type == "bool" && size == 1) {
dv.setInt8(offset, !!value ? 1 : 0, jsb.__isLittleEndian__);
} else if(type == "Color4B" && size == 4) {
dv.setUint8(offset, value.r);
dv.setUint8(offset + 1, value.g);
dv.setUint8(offset + 2, value.b);
dv.setUint8(offset + 3, value.a);
} else if(type == "int8" && size == 1) {
dv.setUint8(offset, value);
} else {
cc.warn("dont know how to set value to buffer, type/size -> " + type+"/"+size + ".");
}
}
_setFieldValue(dv, desc, field_name, value) {
let field = desc[field_name];
this._setBufferValue(dv, field.offset, field.size, field.type, value);
}
_getBufferValue(dv, offset, size, type) {
if(type == "float" && size == 4) {
return dv.getFloat32(offset, jsb.__isLittleEndian__);
} else if(type == "int32" && size == 4) {
return dv.getInt32(offset, jsb.__isLittleEndian__);
} else if (type == "bool" && size == 1) {
return dv.getInt8(offset, jsb.__isLittleEndian__) != 0;
} else if(type == "Color4B" && size == 4) {
let r = dv.getUint8(offset);
let g = dv.getUint8(offset + 1);
let b = dv.getUint8(offset + 2);
let a = dv.getUint8(offset + 3);
return {r, g, b, a};
} else if(type == "int8" && size == 1) {
return dv.getUint8(offset);
} else {
cc.warn("dont know how to get value from buffer, type/size -> " + type+"/"+size + ".");
return undefined;
}
}
_getFieldValue(dv, desc, field_name) {
let field = desc[field_name];
return this._getBufferValue(dv, field.offset, field.size, field.type);
}
_getLayoutValue(field_name) {
return this._getFieldValue(this._layoutInfo, this._layoutFields, field_name);
}
_setLayoutValue(field_name, value) {
return this._setFieldValue(this._layoutInfo, this._layoutFields, field_name, value);
}
_updateCfgFlag_Content() {
this._updateCfgFlag(UPDATE_CONTENT);
}
_updateCfgFlag_Font() {
this._updateCfgFlag(UPDATE_FONT);
}
_colorEqual(a, b) {
return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a;
}
_colorToObj(r, g, b, a) {
return {r, g, b, a};
}
setString(str)
{
if(str != this._layout.string) {
this._layout.string = str;
this._updateCfgFlag_Content();
}
}
setFontPath(path) {
if(path != this._layout.fontPath) {
this._layout.fontPath = path;
this._updateCfgFlag_Font();
}
}
setFontSize(fontSize, fontSizeRetina)
{
let oldfontsize = this._getFieldValue(this._cfg, this._cfgFields, "fontSize");
if(oldfontsize != fontSize) {
this._setFieldValue(this._cfg, this._cfgFields, "fontSize", fontSize);
this._setFieldValue(this._cfg, this._cfgFields, "fontSizeRetina", fontSizeRetina);
this._updateCfgFlag_Font();
}
}
setOutline(outline) {
let oldOutline = this._getLayoutValue("outlineSize");
if((oldOutline > 0) != (outline > 0)) {
this._updateCfgFlag_Font();
}
if(oldOutline != outline) {
this._updateCfgFlag_Content();
this._setLayoutValue("outlineSize", outline);
}
}
setOutlineColor(color) {
let oldColor = this._getLayoutValue( "outlineColor");
if(!this._colorEqual(oldColor, color)) {
this._setLayoutValue("outlineColor", color);
this._updateCfgFlag_Content();
}
}
setLineHeight(lineHeight) {
let oldLineHeight = this._getLayoutValue("lineHeight");
if(oldLineHeight != lineHeight) {
this._setLayoutValue("lineHeight", lineHeight);
this._updateCfgFlag_Content();
}
}
setOverFlow(overflow) {
let oldValue = this._getLayoutValue("overflow");
if(oldValue != overflow) {
this._setLayoutValue("overflow", overflow);
this._updateCfgFlag_Content();
}
}
setEnableWrap(value) {
let oldValue = this._getLayoutValue("wrap");
if(oldValue != value) {
this._setLayoutValue("wrap", value);
this._updateCfgFlag_Content();
}
}
setVerticalAlign(value) {
let oldValue = this._getLayoutValue("valign");
if(oldValue != value) {
this._setLayoutValue("valign", value);
this._updateCfgFlag_Content();
}
}
setHorizontalAlign(value) {
let oldValue = this._getLayoutValue("halign");
if(oldValue != value) {
this._setLayoutValue("halign", value);
this._updateCfgFlag_Content();
}
}
setContentSize(width, height) {
let oldWidth = this._getLayoutValue("width");
let oldHeight = this._getLayoutValue("height");
if(oldWidth != width || oldHeight != height) {
this._setLayoutValue("height", height);
this._setLayoutValue("width", width);
this._updateCfgFlag_Content();
}
}
setAnchorPoint(x, y) {
let oldX = this._getLayoutValue("anchorX");
let oldY = this._getLayoutValue("anchorY");
if(oldX != x || oldY != y) {
this._setLayoutValue("anchorX", x);
this._setLayoutValue("anchorY", y);
this._updateCfgFlag_Content();
}
}
setColor(color) {
let oldColor = this._getLayoutValue("color");
if(!this._colorEqual(oldColor, color)) {
this._setLayoutValue("color", color);
this._updateCfgFlag_Content();
}
}
setShadow( x, y, blur) {
let oldBlur = this._getLayoutValue("shadowBlur");
let oldX = this._getLayoutValue("shadowX");
let oldY = this._getLayoutValue("shadowY");
if((oldBlur > 0) != (blur > 0)) {
this._updateCfgFlag_Font();
}
let updateContent = false;
if(oldBlur != blur) {
this._setLayoutValue("shadowBlur", blur);
updateContent = true;
}
if(oldX != x) {
this._setLayoutValue("shadowX", x);
updateContent = true;
}
if(oldY != y) {
this._setLayoutValue("shadowY", y);
updateContent = true;
}
if(updateContent) {
this._updateCfgFlag_Content();
}
}
setShadowColor(color) {
let oldColor = this._getLayoutValue("shadowColor");
if(!this._colorEqual(oldColor, color)) {
this._setLayoutValue("shadowColor", color);
this._updateCfgFlag_Content();
}
}
setItalic(enabled) {
let oldItalic = this._getLayoutValue("italic");
if(oldItalic!=enabled) {
this._setLayoutValue("italic", enabled);
this._updateCfgFlag_Content();
}
}
setBold(bold) {
let oldBold = this._getLayoutValue("bold");
if(oldBold!=bold) {
this._setLayoutValue("bold", bold);
this._updateCfgFlag_Content();
this._updateCfgFlag_Font(); //enable sdf
}
}
setUnderline(underline)
{
let oldBold = this._getLayoutValue("underline");
if(oldBold != underline) {
this._setLayoutValue("underline", underline);
this._updateCfgFlag_Content();
}
}
setSpacingX(x) {
let oldX = this._getLayoutValue("spaceX");
if(oldX != x && typeof x == "number" && ! isNaN(x)) {
this._setLayoutValue("spaceX", x);
this._updateCfgFlag_Content();
}
}
updateRenderData(comp) {
if (!comp._vertsDirty) return;
if (comp.font && comp.font.nativeUrl) {
this.setFontPath(cc.assetManager.cacheManager.getCache(comp.font.nativeUrl) || comp.font.nativeUrl);
}
let layout = this._layout;
let c = comp.node.color;
let node = comp.node;
let retinaSize = comp.fontSize;
this.setString(comp.string);
this.setFontSize(comp.fontSize, retinaSize / 72 * comp.fontSize);
this.setLineHeight(comp.lineHeight);
this.setEnableWrap(comp.enableWrapText);
this.setItalic(comp.enableItalic);
this.setUnderline(comp.enableUnderline);
this.setBold(comp.enableBold);
this.setOverFlow(comp.overflow);
this.setVerticalAlign(comp.verticalAlign);
this.setHorizontalAlign(comp.horizontalAlign);
this.setSpacingX(comp.spacingX);
this.setContentSize(node.getContentSize().width, node.getContentSize().height);
this.setAnchorPoint(node.anchorX, node.anchorY);
this.setColor(this._colorToObj(c.getR(), c.getG(), c.getB(), Math.ceil(c.getA() * node.opacity / 255)));
let shadow = node.getComponent(cc.LabelShadow);
if (shadow && shadow.enabled) {
let shadowColor = shadow.color;
this.setShadow(shadow.offset.x, shadow.offset.y, shadow.blur);
this.setShadowColor(this._colorToObj(shadowColor.getR(), shadowColor.getG(), shadowColor.getB(), Math.ceil(shadowColor.getA() * node.opacity / 255)));
} else {
this.setShadow(0, 0, -1);
}
this._updateTTFMaterial(comp);
layout.render();
//comp._vertsDirty = false;
}
_bindMaterial(comp) {
let material = this.labelMaterial;
if(!material) {
material = MaterialVariant.createWithBuiltin("2d-label", comp);
this.labelMaterial = material;
}
return material;
}
_updateTTFMaterial(comp) {
let material = this._bindMaterial(comp)
let node = this._label.node;
let layout = this._layout;
let outline = node.getComponent(cc.LabelOutline);
let outlineSize = 0;
if (outline && outline.enabled && outline.width > 0) {
outlineSize = Math.max(Math.min(outline.width / 10, 0.4), 0.1);
let c = outline.color;
this.setOutlineColor(this._colorToObj(c.getR(), c.getG(), c.getB(), Math.ceil(c.getA() * node.opacity / 255)));
}
this.setOutline(outlineSize);
material.define('CC_USE_MODEL', true);
material.define('USE_TEXTURE_ALPHAONLY', true);
material.define('USE_SDF', outlineSize > 0.0 || comp.enableBold );
material.define('USE_SDF_EXTEND', comp.enableBold ? 1 : 0);
if (material.getDefine('CC_SUPPORT_standard_derivatives') !== undefined && cc.sys.glExtension('OES_standard_derivatives')) {
material.define('CC_SUPPORT_standard_derivatives', true);
}
layout.setEffect(material.effect._nativeObj);
}
fillBuffers (comp, renderer) {
this._layout.render();
}
getVfmt() {
}
}

View File

@@ -0,0 +1,101 @@
/****************************************************************************
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 TTFAssembler from '../../../../utils/label/ttf';
const LabelShadow = require('../../../../../components/CCLabelShadow');
const WHITE = cc.color(255, 255, 255, 255);
export default class WebglTTFAssembler extends TTFAssembler {
updateUVs (comp) {
let verts = this._renderData.vDatas[0];
let uv = comp._frame.uv;
let uvOffset = this.uvOffset;
let floatsPerVert = this.floatsPerVert;
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];
}
}
updateColor (comp) {
WHITE._fastSetA(comp.node._color.a);
let color = WHITE._val;
super.updateColor(comp, color);
}
updateVerts (comp) {
let node = comp.node,
canvasWidth = comp._ttfTexture.width,
canvasHeight = comp._ttfTexture.height,
appx = node.anchorX * node.width,
appy = node.anchorY * node.height;
let shadow = LabelShadow && comp.getComponent(LabelShadow);
if (shadow && shadow._enabled) {
// adapt size changed caused by shadow
let offsetX = (canvasWidth - node.width) / 2;
let offsetY = (canvasHeight - node.height) / 2;
let shadowOffset = shadow.offset;
if (-shadowOffset.x > offsetX) {
// expand to left
appx += (canvasWidth - node.width);
}
else if (offsetX > shadowOffset.x) {
// expand to left and right
appx += (offsetX - shadowOffset.x);
}
else {
// expand to right, no need to change render position
}
if (-shadowOffset.y > offsetY) {
// expand to top
appy += (canvasHeight - node.height);
}
else if (offsetY > shadowOffset.y) {
// expand to top and bottom
appy += (offsetY - shadowOffset.y);
}
else {
// expand to bottom, no need to change render position
}
}
let local = this._local;
local[0] = -appx;
local[1] = -appy;
local[2] = canvasWidth - appx;
local[3] = canvasHeight - appy;
this.updateUVs(comp);
this.updateWorldVerts(comp);
}
}

View File

@@ -0,0 +1,53 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
import Vec3 from '../../../../../value-types/vec3';
const Assembler3D = require('../../../../assembler-3d');
const WebglBmfontAssembler = require('../2d/bmfont');
const vec3_temp_local = new Vec3();
const vec3_temp_world = new Vec3();
export default class WebglBmfontAssembler3D extends WebglBmfontAssembler {
}
cc.js.mixin(WebglBmfontAssembler3D.prototype, Assembler3D, {
updateWorldVerts (comp) {
let matrix = comp.node._worldMatrix;
let local = this._local;
let world = this._renderData.vDatas[0];
let floatsPerVert = this.floatsPerVert;
for (let offset = 0; offset < world.length; offset += floatsPerVert) {
Vec3.set(vec3_temp_local, local[offset], local[offset+1], 0);
Vec3.transformMat4(vec3_temp_world, vec3_temp_local, matrix);
world[offset] = vec3_temp_world.x;
world[offset+1] = vec3_temp_world.y;
world[offset+2] = vec3_temp_world.z;
}
}
});

View File

@@ -0,0 +1,54 @@
/****************************************************************************
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 Vec3 from '../../../../../value-types/vec3';
const Assembler3D = require('../../../../assembler-3d');
const WebglLetterFontAssembler = require('../2d/letter');
const vec3_temp_local = new Vec3();
const vec3_temp_world = new Vec3();
export default class WebglLetterFontAssembler3D extends WebglLetterFontAssembler {
}
cc.js.mixin(WebglLetterFontAssembler3D.prototype, Assembler3D, {
updateWorldVerts (comp) {
let matrix = comp.node._worldMatrix;
let local = this._local;
let world = this._renderData.vDatas[0];
let floatsPerVert = this.floatsPerVert;
for (let offset = 0; offset < world.length; offset += floatsPerVert) {
Vec3.set(vec3_temp_local, local[offset], local[offset+1], 0);
Vec3.transformMat4(vec3_temp_world, vec3_temp_local, matrix);
world[offset] = vec3_temp_world.x;
world[offset+1] = vec3_temp_world.y;
world[offset+2] = vec3_temp_world.z;
}
}
});

View File

@@ -0,0 +1,33 @@
/****************************************************************************
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 Assembler3D = require('../../../../assembler-3d');
const WebglTTFAssembler = require('../2d/ttf');
export default class WebglTTFAssembler3D extends WebglTTFAssembler {
}
cc.js.mixin(WebglTTFAssembler3D.prototype, Assembler3D);

View File

@@ -0,0 +1,98 @@
/****************************************************************************
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 '../../../assembler';
import Label from '../../../../components/CCLabel';
import TTF from './2d/ttf';
import Bmfont from './2d/bmfont';
import Letter from './2d/letter';
import TTF3D from './3d/ttf';
import Bmfont3D from './3d/bmfont';
import Letter3D from './3d/letter';
let NativeTTF = undefined;
if(CC_JSB) {
NativeTTF = require("./2d/nativeTTF");
}
Label._canvasPool = {
pool: [],
get () {
let data = this.pool.pop();
if (!data) {
let canvas = document.createElement("canvas");
let context = canvas.getContext("2d");
data = {
canvas: canvas,
context: context
}
// default text info
context.textBaseline = 'alphabetic';
}
return data;
},
put (canvas) {
if (this.pool.length >= 32) {
return;
}
this.pool.push(canvas);
}
};
Assembler.register(cc.Label, {
getConstructor(label) {
let is3DNode = label.node.is3DNode;
let ctor = is3DNode ? TTF3D : TTF;
if (label.font instanceof cc.BitmapFont) {
ctor = is3DNode ? Bmfont3D : Bmfont;
} else if (label.cacheMode === Label.CacheMode.CHAR) {
if(CC_JSB && !is3DNode && !!jsb.LabelRenderer && label.font instanceof cc.TTFFont && label._useNativeTTF()){
ctor = NativeTTF;
} else if (cc.sys.platform === cc.sys.WECHAT_GAME_SUB) {
cc.warn('sorry, subdomain does not support CHAR mode currently!');
} else {
ctor = is3DNode ? Letter3D : Letter;
}
}
return ctor;
},
TTF,
Bmfont,
Letter,
TTF3D,
Bmfont3D,
Letter3D,
NativeTTF
});

View File

@@ -0,0 +1,195 @@
/****************************************************************************
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 '../../assembler';
const Mask = require('../../../components/CCMask');
const RenderFlow = require('../../render-flow');
const SimpleSpriteAssembler = require('./sprite/2d/simple');
const GraphicsAssembler = require('./graphics');
const gfx = require('../../../../renderer/gfx');
const vfmtPos = require('../vertex-format').vfmtPos;
// todo: 8 is least Stencil depth supported by webGL device, it could be adjusted to vendor implementation value
let _maxLevel = 8;
// Current mask
let _maskStack = [];
function getWriteMask () {
return 0x01 << (_maskStack.length - 1);
}
function getStencilRef () {
let result = 0;
for (let i = 0; i < _maskStack.length; ++i) {
result += (0x01 << i);
}
return result;
}
function applyStencil (material, func, failOp, ref, stencilMask, writeMask) {
let effect = material.effect;
let zFailOp = gfx.STENCIL_OP_KEEP,
zPassOp = gfx.STENCIL_OP_KEEP;
effect.setStencil(gfx.STENCIL_ENABLE, func, ref, stencilMask, failOp, zFailOp, zPassOp, writeMask);
}
function pushMask (mask) {
if (_maskStack.length + 1 > _maxLevel) {
cc.errorID(9000, _maxLevel);
}
_maskStack.push(mask);
}
function exitMask (mask, renderer) {
if (_maskStack.length === 0) {
cc.errorID(9001);
}
_maskStack.pop();
if (_maskStack.length === 0) {
renderer._flushMaterial(mask._exitMaterial);
}
else {
enableMask(renderer);
}
}
function applyClearMask (mask, renderer) {
let func = gfx.DS_FUNC_NEVER;
let ref = getWriteMask();
let stencilMask = ref;
let writeMask = ref;
let failOp = mask.inverted ? gfx.STENCIL_OP_REPLACE : gfx.STENCIL_OP_ZERO;
applyStencil(mask._clearMaterial, func, failOp, ref, stencilMask, writeMask);
let buffer = renderer.getBuffer('mesh', vfmtPos);
let offsetInfo = buffer.request(4, 6);
let indiceOffset = offsetInfo.indiceOffset,
vertexOffset = offsetInfo.byteOffset >> 2,
vertexId = offsetInfo.vertexOffset,
vbuf = buffer._vData,
ibuf = buffer._iData;
vbuf[vertexOffset++] = -1;
vbuf[vertexOffset++] = -1;
vbuf[vertexOffset++] = -1;
vbuf[vertexOffset++] = 1;
vbuf[vertexOffset++] = 1;
vbuf[vertexOffset++] = 1;
vbuf[vertexOffset++] = 1;
vbuf[vertexOffset++] = -1;
ibuf[indiceOffset++] = vertexId;
ibuf[indiceOffset++] = vertexId + 3;
ibuf[indiceOffset++] = vertexId + 1;
ibuf[indiceOffset++] = vertexId + 1;
ibuf[indiceOffset++] = vertexId + 3;
ibuf[indiceOffset++] = vertexId + 2;
renderer.node = renderer._dummyNode;
renderer.material = mask._clearMaterial;
renderer._flush();
}
function applyAreaMask (mask, renderer) {
let func = gfx.DS_FUNC_NEVER;
let ref = getWriteMask();
let stencilMask = ref;
let writeMask = ref;
let failOp = mask.inverted ? gfx.STENCIL_OP_ZERO : gfx.STENCIL_OP_REPLACE;
applyStencil(mask._materials[0], func, failOp, ref, stencilMask, writeMask);
// vertex buffer
renderer.material = mask._materials[0];
if (mask._type === Mask.Type.IMAGE_STENCIL) {
renderer.node = renderer._dummyNode;
SimpleSpriteAssembler.prototype.fillBuffers.call(mask._assembler, mask, renderer);
renderer._flush();
}
else {
renderer.node = mask.node;
GraphicsAssembler.prototype.fillBuffers.call(mask._graphics._assembler, mask._graphics, renderer);
}
}
function enableMask (renderer) {
let func = gfx.DS_FUNC_EQUAL;
let failOp = gfx.STENCIL_OP_KEEP;
let ref = getStencilRef();
let stencilMask = ref;
let writeMask = getWriteMask();
let mask = _maskStack[_maskStack.length - 1];
applyStencil(mask._enableMaterial, func, failOp, ref, stencilMask, writeMask);
renderer._flushMaterial(mask._enableMaterial);
}
export class MaskAssembler extends SimpleSpriteAssembler {
updateRenderData (mask) {
if (mask._type === Mask.Type.IMAGE_STENCIL) {
if (mask.spriteFrame) {
SimpleSpriteAssembler.prototype.updateRenderData.call(this, mask);
}
else {
mask.setMaterial(0, null);
}
}
else {
mask._graphics.setMaterial(0, mask._materials[0]);
GraphicsAssembler.prototype.updateRenderData.call(mask._graphics._assembler, mask._graphics, mask._graphics);
}
}
fillBuffers (mask, renderer) {
// Invalid state
if (mask._type !== Mask.Type.IMAGE_STENCIL || mask.spriteFrame) {
// HACK: Must push mask after batch, so we can only put this logic in fillVertexBuffer or fillIndexBuffer
pushMask(mask);
applyClearMask(mask, renderer);
applyAreaMask(mask, renderer);
enableMask(renderer);
}
mask.node._renderFlag |= RenderFlow.FLAG_UPDATE_RENDER_DATA;
}
postFillBuffers (mask, renderer) {
// Invalid state
if (mask._type !== Mask.Type.IMAGE_STENCIL || mask.spriteFrame) {
// HACK: Must pop mask after batch, so we can only put this logic in fillBuffers
exitMask(mask, renderer);
}
mask.node._renderFlag |= RenderFlow.FLAG_UPDATE_RENDER_DATA;
}
};
Assembler.register(Mask, MaskAssembler);

View File

@@ -0,0 +1,271 @@
/****************************************************************************
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 Assembler2D from '../../assembler-2d';
const MotionStreak = require('../../../components/CCMotionStreak');
const RenderFlow = require('../../render-flow');
function Point (point, dir) {
this.point = point || cc.v2();
this.dir = dir || cc.v2();
this.distance = 0;
this.time = 0;
}
Point.prototype.setPoint = function (x, y) {
this.point.x = x;
this.point.y = y;
};
Point.prototype.setDir = function (x, y) {
this.dir.x = x;
this.dir.y = y;
};
let _tangent = cc.v2();
let _miter = cc.v2();
let _normal = cc.v2();
let _vec2 = cc.v2();
function normal (out, dir) {
//get perpendicular
out.x = -dir.y;
out.y = dir.x;
return out
}
function computeMiter (miter, lineA, lineB, halfThick, maxMultiple) {
//get tangent line
lineA.add(lineB, _tangent);
_tangent.normalizeSelf();
//get miter as a unit vector
miter.x = -_tangent.y;
miter.y = _tangent.x;
_vec2.x = -lineA.y;
_vec2.y = lineA.x;
//get the necessary length of our miter
let multiple = 1 / miter.dot(_vec2);
if (maxMultiple) {
multiple = Math.min(multiple, maxMultiple);
}
return halfThick * multiple;
}
export default class MotionStreakAssembler extends Assembler2D {
constructor () {
super();
this._tailShortenTime = 0;
}
initData () {
this._renderData.createFlexData(0, 16, (16 - 2) * 3);
}
update (comp, dt) {
if (CC_EDITOR && !comp.preview) return;
let stroke = comp._stroke / 2;
let node = comp.node;
let matrix = node._worldMatrix.m;
let tx = matrix[12], ty = matrix[13];
let points = comp._points;
let lastPos = comp._lastWPos;
let fadeTime = comp._fadeTime;
let moved = lastPos.x !== tx || lastPos.y !== ty;
if (moved) {
let cur;
let newHead = false;
if (points.length === 0) {
// new
let prev = new Point();
prev.setPoint(lastPos.x, lastPos.y);
this._tailShortenTime = prev.time = fadeTime;
points.push(prev);
cur = new Point();
points.unshift(cur);
}
else {
// check moved distance
cur = points[0];
let prev = points[1];
let difx = prev.point.x - tx;
let dify = prev.point.y - ty;
newHead = ((difx*difx + dify*dify) >= comp.minSeg*comp.minSeg);
}
// update head
cur.setPoint(tx, ty);
cur.time = fadeTime + dt;
let prev = points[1];
cur.distance = cur.point.sub(prev.point, _vec2).mag();
_vec2.normalizeSelf();
cur.setDir(_vec2.x, _vec2.y);
let prevIsTail = points.length === 2;
if (prevIsTail) {
prev.setDir(_vec2.x, _vec2.y);
}
if (newHead) {
let point = new Point(cur.point.clone(), cur.dir.clone());
point.distance = cur.distance;
point.time = cur.time;
points.unshift(point);
}
}
lastPos.x = tx;
lastPos.y = ty;
if (points.length < 2) {
return;
}
// cc.log(points.map(x => x.time.toFixed(2)).reverse().join(' '), ',', this._tailShortenTime.toFixed(2));
let color = comp._color, ca = color.a;
let crgb = (color.b<<16) | (color.g<<8) | color.r;
let verticesCount = 0;
let indicesCount = 0;
let flexBuffer = this._renderData._flexBuffer;
flexBuffer.reserve(points.length*2, (points.length-1)*6);
let vData = flexBuffer.vData;
let uintVData = flexBuffer.uintVData;
let vertsOffset = 5;
for (let i = points.length - 1; i >=0 ; i--) {
let p = points[i];
let point = p.point;
let dir = p.dir;
p.time -= dt;
let isLast = i === points.length - 1;
if (p.time <= 0) {
if (isLast && i - 1 >= 0) {
this._tailShortenTime = points[i - 1].time - dt;
}
points.splice(i, 1);
continue;
}
let progress = p.time / fadeTime;
if (isLast) {
let next = points[i - 1];
if (!next) {
points.splice(i, 1);
continue;
}
let nextIsStatic = points.length >= 3;
if (nextIsStatic) {
let segmentProgress = p.time / this._tailShortenTime;
if (segmentProgress <= 1) {
point.x = next.point.x - next.distance * next.dir.x * segmentProgress;
point.y = next.point.y - next.distance * next.dir.y * segmentProgress;
}
}
else {
this._tailShortenTime = p.time;
}
}
normal(_normal, dir);
let da = progress * ca;
let c = ((da<<24) >>> 0) | crgb;
let offset = verticesCount * vertsOffset;
vData[offset] = point.x + _normal.x * stroke;
vData[offset + 1] = point.y + _normal.y * stroke;
vData[offset + 2] = 1;
vData[offset + 3] = progress;
uintVData[offset + 4] = c;
offset += vertsOffset;
vData[offset] = point.x - _normal.x * stroke;
vData[offset + 1] = point.y - _normal.y * stroke;
vData[offset + 2] = 0;
vData[offset + 3] = progress;
uintVData[offset + 4] = c;
verticesCount += 2;
}
indicesCount = verticesCount <= 2 ? 0 : (verticesCount - 2) * 3;
flexBuffer.used(verticesCount, indicesCount);
}
fillBuffers (comp, renderer) {
let { vData, usedVertices, usedIndices, usedVerticesFloats } = this._renderData._flexBuffer;
let buffer = renderer._meshBuffer;
let offsetInfo = buffer.request(usedVertices, usedIndices);
// 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, usedVerticesFloats), vertexOffset);
}
else {
vbuf.set(vData, vertexOffset);
}
// fill indices
let ibuf = buffer._iData,
indiceOffset = offsetInfo.indiceOffset,
vertexId = offsetInfo.vertexOffset;
// index buffer
for (let i = 0, l = usedVertices; i < l; i += 2) {
let start = vertexId + i;
ibuf[indiceOffset++] = start;
ibuf[indiceOffset++] = start + 2;
ibuf[indiceOffset++] = start + 1;
ibuf[indiceOffset++] = start + 1;
ibuf[indiceOffset++] = start + 2;
ibuf[indiceOffset++] = start + 3;
}
comp.node._renderFlag |= RenderFlow.FLAG_UPDATE_RENDER_DATA;
}
}
MotionStreakAssembler.register(MotionStreak, MotionStreakAssembler);

View File

@@ -0,0 +1,167 @@
/****************************************************************************
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 Assembler2D from '../../../../assembler-2d';
const Sprite = require('../../../../../components/CCSprite');
const FillType = Sprite.FillType;
export default class BarFilledAssembler extends Assembler2D {
updateRenderData (sprite) {
let frame = sprite._spriteFrame;
this.packToDynamicAtlas(sprite, frame);
if (!sprite._vertsDirty) {
return;
}
let fillStart = sprite._fillStart;
let fillRange = sprite._fillRange;
if (fillRange < 0) {
fillStart += fillRange;
fillRange = -fillRange;
}
fillRange = fillStart + fillRange;
fillStart = fillStart > 1.0 ? 1.0 : fillStart;
fillStart = fillStart < 0.0 ? 0.0 : fillStart;
fillRange = fillRange > 1.0 ? 1.0 : fillRange;
fillRange = fillRange < 0.0 ? 0.0 : fillRange;
fillRange = fillRange - fillStart;
fillRange = fillRange < 0 ? 0 : fillRange;
let fillEnd = fillStart + fillRange;
fillEnd = fillEnd > 1 ? 1 : fillEnd;
this.updateUVs(sprite, fillStart, fillEnd);
this.updateVerts(sprite, fillStart, fillEnd);
sprite._vertsDirty = false;
}
updateUVs (sprite, fillStart, fillEnd) {
let spriteFrame = sprite._spriteFrame;
//build uvs
let atlasWidth = spriteFrame._texture.width;
let atlasHeight = spriteFrame._texture.height;
let textureRect = spriteFrame._rect;
//uv computation should take spritesheet into account.
let ul, vb, ur, vt;
let quadUV0, quadUV1, quadUV2, quadUV3, quadUV4, quadUV5, quadUV6, quadUV7;
if (spriteFrame._rotated) {
ul = (textureRect.x) / atlasWidth;
vb = (textureRect.y + textureRect.width) / atlasHeight;
ur = (textureRect.x + textureRect.height) / atlasWidth;
vt = (textureRect.y) / atlasHeight;
quadUV0 = quadUV2 = ul;
quadUV4 = quadUV6 = ur;
quadUV3 = quadUV7 = vb;
quadUV1 = quadUV5 = vt;
}
else {
ul = (textureRect.x) / atlasWidth;
vb = (textureRect.y + textureRect.height) / atlasHeight;
ur = (textureRect.x + textureRect.width) / atlasWidth;
vt = (textureRect.y) / atlasHeight;
quadUV0 = quadUV4 = ul;
quadUV2 = quadUV6 = ur;
quadUV1 = quadUV3 = vb;
quadUV5 = quadUV7 = vt;
}
let verts = this._renderData.vDatas[0];
let uvOffset = this.uvOffset;
let floatsPerVert = this.floatsPerVert;
switch (sprite._fillType) {
case FillType.HORIZONTAL:
verts[uvOffset] = quadUV0 + (quadUV2 - quadUV0) * fillStart;
verts[uvOffset + 1] = quadUV1 + (quadUV3 - quadUV1) * fillStart;
verts[uvOffset + floatsPerVert] = quadUV0 + (quadUV2 - quadUV0) * fillEnd;
verts[uvOffset + floatsPerVert + 1] = quadUV1 + (quadUV3 - quadUV1) * fillEnd;
verts[uvOffset + floatsPerVert * 2] = quadUV4 + (quadUV6 - quadUV4) * fillStart;
verts[uvOffset + floatsPerVert * 2 + 1] = quadUV5 + (quadUV7 - quadUV5) * fillStart;
verts[uvOffset + floatsPerVert * 3] = quadUV4 + (quadUV6 - quadUV4) * fillEnd;
verts[uvOffset + floatsPerVert * 3 + 1] = quadUV5 + (quadUV7 - quadUV5) * fillEnd;
break;
case FillType.VERTICAL:
verts[uvOffset] = quadUV0 + (quadUV4 - quadUV0) * fillStart;
verts[uvOffset + 1] = quadUV1 + (quadUV5 - quadUV1) * fillStart;
verts[uvOffset + floatsPerVert] = quadUV2 + (quadUV6 - quadUV2) * fillStart;
verts[uvOffset + floatsPerVert + 1] = quadUV3 + (quadUV7 - quadUV3) * fillStart;
verts[uvOffset + floatsPerVert * 2] = quadUV0 + (quadUV4 - quadUV0) * fillEnd;
verts[uvOffset + floatsPerVert * 2 + 1] = quadUV1 + (quadUV5 - quadUV1) * fillEnd;
verts[uvOffset + floatsPerVert * 3] = quadUV2 + (quadUV6 - quadUV2) * fillEnd;
verts[uvOffset + floatsPerVert * 3 + 1] = quadUV3 + (quadUV7 - quadUV3) * fillEnd;
break;
default:
cc.errorID(2626);
break;
}
}
updateVerts (sprite, fillStart, fillEnd) {
let node = sprite.node,
width = node.width, height = node.height,
appx = node.anchorX * width, appy = node.anchorY * height;
let l = -appx, b = -appy,
r = width - appx, t = height - appy;
let progressStart, progressEnd;
switch (sprite._fillType) {
case FillType.HORIZONTAL:
progressStart = l + (r - l) * fillStart;
progressEnd = l + (r - l) * fillEnd;
l = progressStart;
r = progressEnd;
break;
case FillType.VERTICAL:
progressStart = b + (t - b) * fillStart;
progressEnd = b + (t - b) * fillEnd;
b = progressStart;
t = progressEnd;
break;
default:
cc.errorID(2626);
break;
}
let local = this._local;
local[0] = l;
local[1] = b;
local[2] = r;
local[3] = t;
this.updateWorldVerts(sprite);
}
}

View File

@@ -0,0 +1,148 @@
/****************************************************************************
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 Assembler2D from '../../../../assembler-2d';
export default class MeshSpriteAssembler extends Assembler2D {
initData (sprite) {
this._renderData.createFlexData(0, 4, 6, this.getVfmt());
}
updateRenderData (sprite) {
this.packToDynamicAtlas(sprite, sprite._spriteFrame);
let frame = sprite.spriteFrame;
if (frame) {
let vertices = frame.vertices;
if (vertices) {
this.verticesCount = vertices.x.length;
this.indicesCount = vertices.triangles.length;
let renderData = this._renderData;
let flexBuffer = renderData._flexBuffer;
if (flexBuffer.reserve(this.verticesCount, this.indicesCount)) {
this.updateColor(sprite);
sprite._vertsDirty = true;
}
flexBuffer.used(this.verticesCount, this.indicesCount);
this.updateIndices(vertices.triangles);
if (sprite._vertsDirty) {
this.updateUVs(sprite);
this.updateVerts(sprite);
this.updateWorldVerts(sprite);
sprite._vertsDirty = false;
}
}
}
}
updateIndices (triangles) {
this._renderData.iDatas[0].set(triangles);
}
updateUVs (sprite) {
let vertices = sprite.spriteFrame.vertices,
u = vertices.nu,
v = vertices.nv;
let uvOffset = this.uvOffset;
let floatsPerVert = this.floatsPerVert;
let verts = this._renderData.vDatas[0];
for (let i = 0; i < u.length; i++) {
let dstOffset = floatsPerVert * i + uvOffset;
verts[dstOffset] = u[i];
verts[dstOffset + 1] = v[i];
}
}
updateVerts (sprite) {
let node = sprite.node,
contentWidth = Math.abs(node.width),
contentHeight = Math.abs(node.height),
appx = node.anchorX * contentWidth,
appy = node.anchorY * contentHeight;
let frame = sprite.spriteFrame,
vertices = frame.vertices,
x = vertices.x,
y = vertices.y,
originalWidth = frame._originalSize.width,
originalHeight = frame._originalSize.height,
rectWidth = frame._rect.width,
rectHeight = frame._rect.height,
offsetX = frame._offset.x,
offsetY = frame._offset.y,
trimX = offsetX + (originalWidth - rectWidth) / 2,
trimY = offsetY + (originalHeight - rectHeight) / 2;
let scaleX = contentWidth / (sprite.trim ? rectWidth : originalWidth),
scaleY = contentHeight / (sprite.trim ? rectHeight : originalHeight);
let local = this._local;
if (!sprite.trim) {
for (let i = 0, l = x.length; i < l; i++) {
let offset = i * 2;
local[offset] = (x[i]) * scaleX - appx;
local[offset + 1] = (originalHeight - y[i]) * scaleY - appy;
}
}
else {
for (let i = 0, l = x.length; i < l; i++) {
let offset = i * 2;
local[offset] = (x[i] - trimX) * scaleX - appx;
local[offset + 1] = (originalHeight - y[i] - trimY) * scaleY - appy;
}
}
if (frame._flipX) {
for (let i = 0, l = this.verticesCount; i < l; i++) {
local[i * 2] = contentWidth - local[i * 2] - 2 * appx;
}
}
if (frame._flipY) {
for (let i = 0, l = this.verticesCount; i < l; i++) {
local[i * 2 + 1] = contentHeight - local[i * 2 + 1] - 2 * appy;
}
}
}
updateWorldVerts (sprite) {
let node = sprite.node;
let matrix = node._worldMatrix;
let matrixm = matrix.m;
let a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
tx = matrixm[12], ty = matrixm[13];
let local = this._local;
let world = this._renderData.vDatas[0];
let floatsPerVert = this.floatsPerVert;
for (let i = 0, l = this.verticesCount; i < l; i++) {
let lx = local[i*2];
let ly = local[i*2 + 1];
world[floatsPerVert * i] = lx * a + ly * c + tx;
world[floatsPerVert * i + 1] = lx * b + ly * d + ty;
}
}
}

View File

@@ -0,0 +1,371 @@
/****************************************************************************
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 Assembler2D from '../../../../assembler-2d';
const PI_2 = Math.PI * 2;
let _vertPos = [cc.v2(0, 0), cc.v2(0, 0), cc.v2(0, 0), cc.v2(0, 0)];
let _vertices = [0, 0, 0, 0];
let _uvs = [0, 0, 0, 0, 0, 0, 0, 0];
let _intersectPoint_1 = [cc.v2(0, 0), cc.v2(0, 0), cc.v2(0, 0), cc.v2(0, 0)];
let _intersectPoint_2 = [cc.v2(0, 0), cc.v2(0, 0), cc.v2(0, 0), cc.v2(0, 0)];
let _center = cc.v2(0, 0);
let _triangles = [];
function _calcInsectedPoints (left, right, bottom, top, center, angle, intersectPoints) {
//left bottom, right, top
let sinAngle = Math.sin(angle);
let cosAngle = Math.cos(angle);
let tanAngle, cotAngle;
if (Math.cos(angle) !== 0) {
tanAngle = sinAngle / cosAngle;
//calculate right and left
if ((left - center.x) * cosAngle > 0) {
let yleft = center.y + tanAngle * (left - center.x);
intersectPoints[0].x = left;
intersectPoints[0].y = yleft;
}
if ((right - center.x) * cosAngle > 0) {
let yright = center.y + tanAngle * (right - center.x);
intersectPoints[2].x = right;
intersectPoints[2].y = yright;
}
}
if (Math.sin(angle) !== 0) {
cotAngle = cosAngle / sinAngle;
//calculate top and bottom
if ((top - center.y) * sinAngle > 0) {
let xtop = center.x + cotAngle * (top - center.y);
intersectPoints[3].x = xtop;
intersectPoints[3].y = top;
}
if ((bottom - center.y) * sinAngle > 0) {
let xbottom = center.x + cotAngle * (bottom - center.y);
intersectPoints[1].x = xbottom;
intersectPoints[1].y = bottom;
}
}
}
function _calculateVertices (sprite) {
let node = sprite.node,
width = node.width, height = node.height,
appx = node.anchorX * width, appy = node.anchorY * height;
let l = -appx, b = -appy,
r = width - appx, t = height - appy;
let vertices = _vertices;
vertices[0] = l;
vertices[1] = b;
vertices[2] = r;
vertices[3] = t;
let fillCenter = sprite._fillCenter,
cx = _center.x = Math.min(Math.max(0, fillCenter.x), 1) * (r - l) + l,
cy = _center.y = Math.min(Math.max(0, fillCenter.y), 1) * (t - b) + b;
_vertPos[0].x = _vertPos[3].x = l;
_vertPos[1].x = _vertPos[2].x = r;
_vertPos[0].y = _vertPos[1].y = b;
_vertPos[2].y = _vertPos[3].y = t;
_triangles.length = 0;
if (cx !== vertices[0]) {
_triangles[0] = [3, 0];
}
if (cx !== vertices[2]) {
_triangles[2] = [1, 2];
}
if (cy !== vertices[1]) {
_triangles[1] = [0, 1];
}
if (cy !== vertices[3]) {
_triangles[3] = [2, 3];
}
}
function _calculateUVs (spriteFrame) {
let atlasWidth = spriteFrame._texture.width;
let atlasHeight = spriteFrame._texture.height;
let textureRect = spriteFrame._rect;
let u0, u1, v0, v1;
let uvs = _uvs;
if (spriteFrame._rotated) {
u0 = (textureRect.x) / atlasWidth;
u1 = (textureRect.x + textureRect.height) / atlasWidth;
v0 = (textureRect.y) / atlasHeight;
v1 = (textureRect.y + textureRect.width) / atlasHeight;
uvs[0] = uvs[2] = u0;
uvs[4] = uvs[6] = u1;
uvs[3] = uvs[7] = v1;
uvs[1] = uvs[5] = v0;
}
else {
u0 = (textureRect.x) / atlasWidth;
u1 = (textureRect.x + textureRect.width) / atlasWidth;
v0 = (textureRect.y) / atlasHeight;
v1 = (textureRect.y + textureRect.height) / atlasHeight;
uvs[0] = uvs[4] = u0;
uvs[2] = uvs[6] = u1;
uvs[1] = uvs[3] = v1;
uvs[5] = uvs[7] = v0;
}
}
function _getVertAngle (start, end) {
let placementX, placementY;
placementX = end.x - start.x;
placementY = end.y - start.y;
if (placementX === 0 && placementY === 0) {
return undefined;
} else if (placementX === 0) {
if (placementY > 0) {
return Math.PI * 0.5;
} else {
return Math.PI * 1.5;
}
} else {
let angle = Math.atan(placementY / placementX);
if (placementX < 0) {
angle += Math.PI;
}
return angle;
}
}
export default class RadialFilledAssembler extends Assembler2D {
initData (sprite) {
this._renderData.createFlexData(0, 4, 6, this.getVfmt());
this.updateIndices();
}
updateRenderData (sprite) {
super.updateRenderData(sprite);
let frame = sprite.spriteFrame;
this.packToDynamicAtlas(sprite, frame);
if (sprite._vertsDirty) {
let fillStart = sprite._fillStart;
let fillRange = sprite._fillRange;
if (fillRange < 0) {
fillStart += fillRange;
fillRange = -fillRange;
}
//do round fill start [0,1), include 0, exclude 1
while (fillStart >= 1.0) fillStart -= 1.0;
while (fillStart < 0.0) fillStart += 1.0;
fillStart *= PI_2;
fillRange *= PI_2;
//build vertices
_calculateVertices(sprite);
//build uvs
_calculateUVs(frame);
_calcInsectedPoints(_vertices[0], _vertices[2], _vertices[1], _vertices[3], _center, fillStart, _intersectPoint_1);
_calcInsectedPoints(_vertices[0], _vertices[2], _vertices[1], _vertices[3], _center, fillStart + fillRange, _intersectPoint_2);
this.updateVerts(sprite, fillStart, fillRange);
sprite._vertsDirty = false;
}
}
updateVerts (sprite, fillStart, fillRange) {
let fillEnd = fillStart + fillRange;
let local = this._local;
local.length = 0;
let offset = 0;
let floatsPerTriangle = 3 * this.floatsPerVert;
for (let triangleIndex = 0; triangleIndex < 4; ++triangleIndex) {
let triangle = _triangles[triangleIndex];
if (!triangle) {
continue;
}
//all in
if (fillRange >= PI_2) {
local.length = offset + floatsPerTriangle;
this._generateTriangle(local, offset, _center, _vertPos[triangle[0]], _vertPos[triangle[1]]);
offset += floatsPerTriangle;
continue;
}
//test against
let startAngle = _getVertAngle(_center, _vertPos[triangle[0]]);
let endAngle = _getVertAngle(_center, _vertPos[triangle[1]]);
if (endAngle < startAngle) endAngle += PI_2;
startAngle -= PI_2;
endAngle -= PI_2;
//testing
for (let testIndex = 0; testIndex < 3; ++testIndex) {
if (startAngle >= fillEnd) {
//all out
} else if (startAngle >= fillStart) {
local.length = offset + floatsPerTriangle;
if (endAngle >= fillEnd) {
//startAngle to fillEnd
this._generateTriangle(local, offset, _center, _vertPos[triangle[0]], _intersectPoint_2[triangleIndex]);
} else {
//startAngle to endAngle
this._generateTriangle(local, offset, _center, _vertPos[triangle[0]], _vertPos[triangle[1]]);
}
offset += floatsPerTriangle;
} else {
//startAngle < fillStart
if (endAngle <= fillStart) {
//all out
} else if (endAngle <= fillEnd) {
local.length = offset + floatsPerTriangle;
//fillStart to endAngle
this._generateTriangle(local, offset, _center, _intersectPoint_1[triangleIndex], _vertPos[triangle[1]]);
offset += floatsPerTriangle;
} else {
local.length = offset + floatsPerTriangle;
//fillStart to fillEnd
this._generateTriangle(local, offset, _center, _intersectPoint_1[triangleIndex], _intersectPoint_2[triangleIndex]);
offset += floatsPerTriangle;
}
}
//add 2 * PI
startAngle += PI_2;
endAngle += PI_2;
}
}
this.allocWorldVerts(sprite);
this.updateWorldVerts(sprite);
}
allocWorldVerts(sprite) {
let color = sprite.node._color._val;
let renderData = this._renderData;
let floatsPerVert = this.floatsPerVert;
let local = this._local;
let verticesCount = local.length / floatsPerVert;
this.verticesCount = this.indicesCount = verticesCount;
let flexBuffer = renderData._flexBuffer;
if (flexBuffer.reserve(verticesCount, verticesCount)) {
this.updateIndices();
}
flexBuffer.used(this.verticesCount, this.indicesCount);
let verts = renderData.vDatas[0],
uintVerts = renderData.uintVDatas[0];
let uvOffset = this.uvOffset;
for (let offset = 0; offset < local.length; offset += floatsPerVert) {
let start = offset + uvOffset;
verts[start] = local[start];
verts[start + 1] = local[start + 1];
uintVerts[start + 2] = color;
}
}
updateIndices () {
let iData = this._renderData.iDatas[0];
for (let i = 0; i < iData.length; i ++) {
iData[i] = i;
}
}
updateWorldVerts (sprite) {
let node = sprite.node;
let matrix = 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 local = this._local;
let world = this._renderData.vDatas[0];
let floatsPerVert = this.floatsPerVert;
for (let offset = 0; offset < local.length; offset += floatsPerVert) {
let x = local[offset];
let y = local[offset + 1];
world[offset] = x * a + y * c + tx;
world[offset+1] = x * b + y * d + ty;
}
}
_generateTriangle (verts, offset, vert0, vert1, vert2) {
let vertices = _vertices;
let v0x = vertices[0];
let v0y = vertices[1];
let v1x = vertices[2];
let v1y = vertices[3];
let floatsPerVert = this.floatsPerVert;
verts[offset] = vert0.x;
verts[offset + 1] = vert0.y;
verts[offset + floatsPerVert] = vert1.x;
verts[offset + floatsPerVert + 1] = vert1.y;
verts[offset + floatsPerVert*2] = vert2.x;
verts[offset + floatsPerVert*2 + 1] = vert2.y;
let uvOffset = this.uvOffset;
let progressX, progressY;
progressX = (vert0.x - v0x) / (v1x - v0x);
progressY = (vert0.y - v0y) / (v1y - v0y);
this._generateUV(progressX, progressY, verts, offset + uvOffset);
progressX = (vert1.x - v0x) / (v1x - v0x);
progressY = (vert1.y - v0y) / (v1y - v0y);
this._generateUV(progressX, progressY, verts, offset + floatsPerVert + uvOffset);
progressX = (vert2.x - v0x) / (v1x - v0x);
progressY = (vert2.y - v0y) / (v1y - v0y);
this._generateUV(progressX, progressY, verts, offset + floatsPerVert*2 + uvOffset);
}
_generateUV (progressX, progressY, verts, offset) {
let uvs = _uvs;
let px1 = uvs[0] + (uvs[2] - uvs[0]) * progressX;
let px2 = uvs[4] + (uvs[6] - uvs[4]) * progressX;
let py1 = uvs[1] + (uvs[3] - uvs[1]) * progressX;
let py2 = uvs[5] + (uvs[7] - uvs[5]) * progressX;
verts[offset] = px1 + (px2 - px1) * progressY;
verts[offset + 1] = py1 + (py2 - py1) * progressY;
}
}

View File

@@ -0,0 +1,86 @@
/****************************************************************************
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 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);
}
}

View File

@@ -0,0 +1,139 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
http://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 Assembler2D from '../../../../assembler-2d';
export default class SlicedAssembler extends Assembler2D {
initData (sprite) {
if (this._renderData.meshCount > 0) return;
this._renderData.createData(0, this.verticesFloats, this.indicesCount);
let indices = this._renderData.iDatas[0];
let indexOffset = 0;
for (let r = 0; r < 3; ++r) {
for (let c = 0; c < 3; ++c) {
let start = r * 4 + c;
indices[indexOffset++] = start;
indices[indexOffset++] = start + 1;
indices[indexOffset++] = start + 4;
indices[indexOffset++] = start + 1;
indices[indexOffset++] = start + 5;
indices[indexOffset++] = start + 4;
}
}
}
initLocal () {
this._local = [];
this._local.length = 8;
}
updateRenderData (sprite) {
let frame = sprite._spriteFrame;
this.packToDynamicAtlas(sprite, frame);
if (sprite._vertsDirty) {
this.updateUVs(sprite);
this.updateVerts(sprite);
sprite._vertsDirty = false;
}
}
updateVerts (sprite) {
let node = sprite.node,
width = node.width, height = node.height,
appx = node.anchorX * width, appy = node.anchorY * height;
let frame = sprite.spriteFrame;
let leftWidth = frame.insetLeft;
let rightWidth = frame.insetRight;
let topHeight = frame.insetTop;
let 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;
// update local
let local = this._local;
local[0] = -appx;
local[1] = -appy;
local[2] = leftWidth * xScale - appx;
local[3] = bottomHeight * yScale - appy;
local[4] = local[2] + sizableWidth;
local[5] = local[3] + sizableHeight;
local[6] = width - appx;
local[7] = height - appy;
this.updateWorldVerts(sprite);
}
updateUVs (sprite) {
let verts = this._renderData.vDatas[0];
let uvSliced = sprite.spriteFrame.uvSliced;
let uvOffset = this.uvOffset;
let floatsPerVert = this.floatsPerVert;
for (let row = 0; row < 4; ++row) {
for (let col = 0; col < 4; ++col) {
let vid = row * 4 + col;
let uv = uvSliced[vid];
let voffset = vid * floatsPerVert;
verts[voffset + uvOffset] = uv.u;
verts[voffset + uvOffset + 1] = uv.v;
}
}
}
updateWorldVerts (sprite) {
let matrix = sprite.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 local = this._local;
let world = this._renderData.vDatas[0];
let floatsPerVert = this.floatsPerVert;
for (let row = 0; row < 4; ++row) {
let localRowY = local[row * 2 + 1];
for (let col = 0; col < 4; ++col) {
let localColX = local[col * 2];
let worldIndex = (row * 4 + col) * floatsPerVert;
world[worldIndex] = localColX * a + localRowY * c + tx;
world[worldIndex + 1] = localColX * b + localRowY * d + ty;
}
}
}
}
Object.assign(SlicedAssembler.prototype, {
verticesCount: 16,
indicesCount: 54
});

View File

@@ -0,0 +1,349 @@
/****************************************************************************
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 Assembler2D from '../../../../assembler-2d';
export default class TiledAssembler extends Assembler2D {
initData (sprite) {
this.verticesCount = 0;
this.contentWidth = 0;
this.contentHeight = 0;
this.rectWidth = 0;
this.rectHeight = 0;
this.hRepeat = 0;
this.vRepeat = 0;
this.row = 0;
this.col = 0;
this._renderData.createFlexData(0, 4, 6, this.getVfmt());
this._updateIndices();
}
initLocal () {
this._local = { x: [], y: []};
}
_updateIndices () {
let iData = this._renderData.iDatas[0];
for (let i = 0, vid = 0, l = iData.length; i < l; i += 6, vid += 4) {
iData[i] = vid;
iData[i + 1] = vid + 1;
iData[i + 2] = vid + 2;
iData[i + 3] = vid + 1;
iData[i + 4] = vid + 3;
iData[i + 5] = vid + 2;
}
}
updateRenderData (sprite) {
let frame = sprite._spriteFrame;
this.packToDynamicAtlas(sprite, frame);
let node = sprite.node;
let contentWidth = this.contentWidth = Math.abs(node.width);
let contentHeight = this.contentHeight = Math.abs(node.height);
let rect = frame._rect;
let leftWidth = frame.insetLeft, rightWidth = frame.insetRight, centerWidth = rect.width - leftWidth - rightWidth,
topHeight = frame.insetTop, bottomHeight = frame.insetBottom, centerHeight = rect.height - topHeight - bottomHeight;
this.sizableWidth = contentWidth - leftWidth - rightWidth;
this.sizableHeight = contentHeight - topHeight - bottomHeight;
this.sizableWidth = this.sizableWidth > 0 ? this.sizableWidth : 0;
this.sizableHeight = this.sizableHeight > 0 ? this.sizableHeight : 0;
let hRepeat = this.hRepeat = centerWidth === 0 ? this.sizableWidth : this.sizableWidth / centerWidth;
let vRepeat = this.vRepeat = centerHeight === 0 ? this.sizableHeight : this.sizableHeight / centerHeight;
let row = this.row = Math.ceil(vRepeat + 2);
let col = this.col = Math.ceil(hRepeat + 2);
// update data property
let count = row * col;
this.verticesCount = count * 4;
this.indicesCount = count * 6;
let renderData = this._renderData;
let flexBuffer = renderData._flexBuffer;
if (flexBuffer.reserve(this.verticesCount, this.indicesCount)) {
this._updateIndices();
this.updateColor(sprite);
}
flexBuffer.used(this.verticesCount, this.indicesCount);
if (sprite._vertsDirty) {
this.updateUVs(sprite);
this.updateVerts(sprite);
sprite._vertsDirty = false;
}
}
updateVerts (sprite) {
let frame = sprite._spriteFrame;
let rect = frame._rect;
let node = sprite.node,
appx = node.anchorX * node.width, appy = node.anchorY * node.height;
let { row, col, contentWidth, contentHeight } = this;
let { x, y } = this._local;
x.length = y.length = 0;
let leftWidth = frame.insetLeft, rightWidth = frame.insetRight, centerWidth = rect.width - leftWidth - rightWidth,
topHeight = frame.insetTop, bottomHeight = frame.insetBottom, centerHeight = rect.height - topHeight - bottomHeight;
let xScale = (node.width / (leftWidth + rightWidth)) > 1 ? 1 : (node.width / (leftWidth + rightWidth));
let yScale = (node.height / (topHeight + bottomHeight)) > 1 ? 1 : (node.height / (topHeight + bottomHeight));
let offsetWidth = 0, offsetHeight = 0;
if (centerWidth > 0) {
/*
* Because the float numerical calculation in javascript is not accurate enough,
* there is an expected result of 1.0, but the actual result is 1.000001.
*/
offsetWidth = Math.floor(this.sizableWidth * 1000) / 1000 % centerWidth === 0 ? centerWidth : this.sizableWidth % centerWidth;
}
else {
offsetWidth = this.sizableWidth;
}
if (centerHeight > 0) {
offsetHeight = Math.floor(this.sizableHeight * 1000) / 1000 % centerHeight === 0 ? centerHeight : this.sizableHeight % centerHeight;
}
else {
offsetHeight = this.sizableHeight;
}
for (let i = 0; i <= col; i++) {
if (i === 0) {
x[i] = - appx;
}
else if (i > 0 && i < col) {
if (i === 1) {
x[i] = leftWidth * xScale + Math.min(centerWidth, this.sizableWidth) - appx;
}
else {
if (centerWidth > 0) {
if (i === (col - 1)) {
x[i] = leftWidth + offsetWidth + centerWidth * (i - 2) - appx;
}
else {
x[i] = leftWidth + Math.min(centerWidth, this.sizableWidth) + centerWidth * (i - 2) - appx;
}
}
else {
x[i] = leftWidth + this.sizableWidth - appx;
}
}
}
else if (i === col) {
x[i] = Math.min(leftWidth + this.sizableWidth + rightWidth, contentWidth) - appx;
}
}
for (let i = 0; i <= row; i++) {
if (i === 0) {
y[i] = - appy;
}
else if (i > 0 && i < row) {
if (i === 1) {
y[i] = bottomHeight * yScale + Math.min(centerHeight, this.sizableHeight) - appy;
}
else {
if (centerHeight > 0) {
if (i === (row - 1)) {
y[i] = bottomHeight + offsetHeight + (i - 2) * centerHeight - appy;
}
else {
y[i] = bottomHeight + Math.min(centerHeight, this.sizableHeight) + (i - 2) * centerHeight - appy;
}
}
else {
y[i] = bottomHeight + this.sizableHeight - appy;
}
}
}
else if (i === row) {
y[i] = Math.min(bottomHeight + this.sizableHeight + topHeight, contentHeight) - appy;
}
}
this.updateWorldVerts(sprite);
}
updateWorldVerts (sprite) {
let renderData = this._renderData;
let local = this._local;
let localX = local.x, localY = local.y;
let world = renderData.vDatas[0];
let { row, col } = this;
let matrix = sprite.node._worldMatrix;
let matrixm = matrix.m;
let a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
tx = matrixm[12], ty = matrixm[13];
let x, x1, y, y1;
let floatsPerVert = this.floatsPerVert;
let vertexOffset = 0;
for (let yindex = 0, ylength = row; yindex < ylength; ++yindex) {
y = localY[yindex];
y1 = localY[yindex + 1];
for (let xindex = 0, xlength = col; xindex < xlength; ++xindex) {
x = localX[xindex];
x1 = localX[xindex + 1];
// lb
world[vertexOffset] = x * a + y * c + tx;
world[vertexOffset + 1] = x * b + y * d + ty;
vertexOffset += floatsPerVert;
// rb
world[vertexOffset] = x1 * a + y * c + tx;
world[vertexOffset + 1] = x1 * b + y * d + ty;
vertexOffset += floatsPerVert;
// lt
world[vertexOffset] = x * a + y1 * c + tx;
world[vertexOffset + 1] = x * b + y1 * d + ty;
vertexOffset += floatsPerVert;
// rt
world[vertexOffset] = x1 * a + y1 * c + tx;
world[vertexOffset + 1] = x1 * b + y1 * d + ty;
vertexOffset += floatsPerVert;
}
}
}
updateUVs (sprite) {
let verts = this._renderData.vDatas[0];
if (!verts) return;
let frame = sprite._spriteFrame;
let rect = frame._rect;
let leftWidth = frame.insetLeft, rightWidth = frame.insetRight, centerWidth = rect.width - leftWidth - rightWidth,
topHeight = frame.insetTop, bottomHeight = frame.insetBottom, centerHeight = rect.height - topHeight - bottomHeight;
let { row, col, hRepeat, vRepeat } = this;
let coefu = 0, coefv = 0;
let uv = sprite.spriteFrame.uv;
let uvSliced = sprite.spriteFrame.uvSliced;
let rotated = sprite.spriteFrame._rotated;
let floatsPerVert = this.floatsPerVert, uvOffset = this.uvOffset;
let tempXVerts = [], tempYVerts = [];
for (let yindex = 0, ylength = row; yindex < ylength; ++yindex) {
if (this.sizableHeight > centerHeight) {
if (this.sizableHeight >= yindex * centerHeight) {
coefv = 1;
}
else {
coefv = vRepeat % 1;
}
}
else {
coefv = vRepeat;
}
for (let xindex = 0, xlength = col; xindex < xlength; ++xindex) {
if (this.sizableWidth > centerWidth) {
if (this.sizableWidth >= xindex * centerWidth) {
coefu = 1;
}
else {
coefu = hRepeat % 1;
}
}
else {
coefu = hRepeat;
}
if (rotated) {
if (yindex === 0) {
tempXVerts[0] = uvSliced[0].u;
tempXVerts[1] = uvSliced[0].u;
tempXVerts[2] = uvSliced[4].u + (uvSliced[8].u - uvSliced[4].u) * coefv;
} else if (yindex < (row - 1)) {
tempXVerts[0] = uvSliced[4].u;
tempXVerts[1] = uvSliced[4].u;
tempXVerts[2] = uvSliced[4].u + (uvSliced[8].u - uvSliced[4].u) * coefv;
} else if (yindex === (row - 1)) {
tempXVerts[0] = uvSliced[8].u;
tempXVerts[1] = uvSliced[8].u;
tempXVerts[2] = uvSliced[12].u;
}
if (xindex === 0) {
tempYVerts[0] = uvSliced[0].v;
tempYVerts[1] = uvSliced[1].v + (uvSliced[2].v - uvSliced[1].v) * coefu;
tempYVerts[2] = uvSliced[0].v;
} else if (xindex < (col - 1)) {
tempYVerts[0] = uvSliced[1].v;
tempYVerts[1] = uvSliced[1].v + (uvSliced[2].v - uvSliced[1].v) * coefu;
tempYVerts[2] = uvSliced[1].v;
} else if (xindex === (col - 1)) {
tempYVerts[0] = uvSliced[2].v;
tempYVerts[1] = uvSliced[3].v;
tempYVerts[2] = uvSliced[2].v;
}
tempXVerts[3] = tempXVerts[2];
tempYVerts[3] = tempYVerts[1];
}
else {
if (xindex === 0) {
tempXVerts[0] = uvSliced[0].u;
tempXVerts[1] = uvSliced[1].u + (uvSliced[2].u - uvSliced[1].u) * coefu;
tempXVerts[2] = uv[0];
} else if (xindex < (col - 1)) {
tempXVerts[0] = uvSliced[1].u;
tempXVerts[1] = uvSliced[1].u + (uvSliced[2].u - uvSliced[1].u) * coefu;
tempXVerts[2] = uvSliced[1].u;
} else if (xindex === (col - 1)) {
tempXVerts[0] = uvSliced[2].u;
tempXVerts[1] = uvSliced[3].u;
tempXVerts[2] = uvSliced[2].u;
}
if (yindex === 0) {
tempYVerts[0] = uvSliced[0].v;
tempYVerts[1] = uvSliced[0].v;
tempYVerts[2] = uvSliced[4].v + (uvSliced[8].v - uvSliced[4].v) * coefv;
} else if (yindex < (row - 1)) {
tempYVerts[0] = uvSliced[4].v;
tempYVerts[1] = uvSliced[4].v;
tempYVerts[2] = uvSliced[4].v + (uvSliced[8].v - uvSliced[4].v) * coefv;
} else if (yindex === (row - 1)) {
tempYVerts[0] = uvSliced[8].v;
tempYVerts[1] = uvSliced[8].v;
tempYVerts[2] = uvSliced[12].v;
}
tempXVerts[3] = tempXVerts[1];
tempYVerts[3] = tempYVerts[2];
}
// lb
verts[uvOffset] = tempXVerts[0];
verts[uvOffset + 1] = tempYVerts[0];
uvOffset += floatsPerVert;
// rb
verts[uvOffset] = tempXVerts[1];
verts[uvOffset + 1] = tempYVerts[1];
uvOffset += floatsPerVert;
// lt
verts[uvOffset] = tempXVerts[2];
verts[uvOffset + 1] = tempYVerts[2];
uvOffset += floatsPerVert;
// rt
verts[uvOffset] = tempXVerts[3];
verts[uvOffset + 1] = tempYVerts[3];
uvOffset += floatsPerVert;
}
}
}
}

View File

@@ -0,0 +1,33 @@
/****************************************************************************
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 Assembler3D = require('../../../../assembler-3d');
const BarFilledAssembler = require('../2d/bar-filled');
export default class BarFilledAssembler3D extends BarFilledAssembler {
}
cc.js.mixin(BarFilledAssembler3D.prototype, Assembler3D);

View File

@@ -0,0 +1,53 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
import Vec3 from '../../../../../value-types/vec3';
const Assembler3D = require('../../../../assembler-3d');
const MeshAssembler = require('../2d/mesh');
let vec3_temp = new Vec3();
export default class MeshAssembler3D extends MeshAssembler {
}
cc.js.mixin(MeshAssembler3D.prototype, Assembler3D, {
updateWorldVerts (comp) {
let matrix = comp.node._worldMatrix;
let local = this._local;
let world = this._renderData.vDatas[0];
let floatsPerVert = this.floatsPerVert;
for (let i = 0, l = local.length/2; i < l; i++) {
Vec3.set(vec3_temp, local[i*2], local[i*2+1], 0);
Vec3.transformMat4(vec3_temp, vec3_temp, matrix);
let dstOffset = floatsPerVert * i;
world[dstOffset] = vec3_temp.x;
world[dstOffset+1] = vec3_temp.y;
world[dstOffset+2] = vec3_temp.z;
}
}
});

View File

@@ -0,0 +1,53 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
import Vec3 from '../../../../../value-types/vec3';
const Assembler3D = require('../../../../assembler-3d');
const RadialFilledAssembler = require('../2d/radial-filled');
const vec3_temp_local = new Vec3();
const vec3_temp_world = new Vec3();
export default class RadialFilledAssembler3D extends RadialFilledAssembler {
}
cc.js.mixin(RadialFilledAssembler3D.prototype, Assembler3D, {
updateWorldVerts (sprite) {
let matrix = sprite.node._worldMatrix;
let local = this._local;
let world = this._renderData.vDatas[0];
let floatsPerVert = this.floatsPerVert;
for (let offset = 0; offset < world.length; offset += floatsPerVert) {
Vec3.set(vec3_temp_local, local[offset], local[offset+1], 0);
Vec3.transformMat4(vec3_temp_world, vec3_temp_local, matrix);
world[offset] = vec3_temp_world.x;
world[offset+1] = vec3_temp_world.y;
world[offset+2] = vec3_temp_world.z;
}
}
});

View File

@@ -0,0 +1,33 @@
/****************************************************************************
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 Assembler3D = require('../../../../assembler-3d');
const SimpleAssembler = require('../2d/simple');
export default class SimpleAssembler3D extends SimpleAssembler {
}
cc.js.mixin(SimpleAssembler3D.prototype, Assembler3D);

View File

@@ -0,0 +1,60 @@
/****************************************************************************
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 Vec3 from '../../../../../value-types/vec3';
const Assembler3D = require('../../../../assembler-3d');
const SlicedAssembler = require('../2d/sliced');
const vec3_temp_local = new Vec3();
const vec3_temp_world = new Vec3();
export default class SlicedAssembler3D extends SlicedAssembler {
}
cc.js.mixin(SlicedAssembler3D.prototype, Assembler3D, {
updateWorldVerts (sprite) {
let matrix = sprite.node._worldMatrix;
let local = this._local;
let world = this._renderData.vDatas[0];
let floatsPerVert = this.floatsPerVert;
for (let row = 0; row < 4; ++row) {
let localRowY = local[row * 2 + 1];
for (let col = 0; col < 4; ++col) {
let localColX = local[col * 2];
Vec3.set(vec3_temp_local, localColX, localRowY, 0);
Vec3.transformMat4(vec3_temp_world, vec3_temp_local, matrix);
let worldIndex = (row * 4 + col) * floatsPerVert;
world[worldIndex] = vec3_temp_world.x;
world[worldIndex+1] = vec3_temp_world.y;
world[worldIndex+2] = vec3_temp_world.z;
}
}
}
});

View File

@@ -0,0 +1,74 @@
/****************************************************************************
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 Vec3 from '../../../../../value-types/vec3';
const Assembler3D = require('../../../../assembler-3d');
const TiledAssembler = require('../2d/tiled');
let vec3_temps = [];
for (let i = 0; i < 4; i++) {
vec3_temps.push(new Vec3);
}
export default class TiledAssembler3D extends TiledAssembler {
}
cc.js.mixin(TiledAssembler3D.prototype, Assembler3D, {
updateWorldVerts (sprite) {
let local = this._local;
let localX = local.x, localY = local.y;
let world = this._renderData.vDatas[0];
let { row, col } = this;
let matrix = sprite.node._worldMatrix;
let x, x1, y, y1;
let vertexOffset = 0;
for (let yindex = 0, ylength = row; yindex < ylength; ++yindex) {
y = localY[yindex];
y1 = localY[yindex + 1];
for (let xindex = 0, xlength = col; xindex < xlength; ++xindex) {
x = localX[xindex];
x1 = localX[xindex + 1];
Vec3.set(vec3_temps[0], x, y, 0);
Vec3.set(vec3_temps[1], x1, y, 0);
Vec3.set(vec3_temps[2], x, y1, 0);
Vec3.set(vec3_temps[3], x1, y1, 0);
for (let i = 0; i < 4; i++) {
let vec3_temp = vec3_temps[i];
Vec3.transformMat4(vec3_temp, vec3_temp, matrix);
let offset = i * 6;
world[vertexOffset + offset] = vec3_temp.x;
world[vertexOffset + offset + 1] = vec3_temp.y;
world[vertexOffset + offset + 2] = vec3_temp.z;
}
vertexOffset += 24;
}
}
}
});

View File

@@ -0,0 +1,60 @@
import Assembler from '../../../assembler';
import { Type, FillType } from '../../../../components/CCSprite';
import Simple from "./2d/simple";
import Sliced from "./2d/sliced";
import Tiled from "./2d/tiled";
import RadialFilled from "./2d/radial-filled";
import BarFilled from "./2d/bar-filled";
import Mesh from './2d/mesh';
import Simple3D from "./3d/simple";
import Sliced3D from "./3d/sliced";
import Tiled3D from "./3d/tiled";
import RadialFilled3D from "./3d/radial-filled";
import BarFilled3D from "./3d/bar-filled";
import Mesh3D from './3d/mesh';
let ctor = {
getConstructor(sprite) {
let is3DNode = sprite.node.is3DNode;
let ctor = is3DNode ? Simple3D : Simple;
switch (sprite.type) {
case Type.SLICED:
ctor = is3DNode ? Sliced3D : Sliced;
break;
case Type.TILED:
ctor = is3DNode ? Tiled3D : Tiled;
break;
case Type.FILLED:
if (sprite._fillType === FillType.RADIAL) {
ctor = is3DNode ? RadialFilled3D : RadialFilled;
} else {
ctor = is3DNode ? BarFilled3D : BarFilled;
}
break;
case Type.MESH:
ctor = is3DNode ? Mesh3D : Mesh;
break;
}
return ctor;
},
Simple,
Sliced,
Tiled,
RadialFilled,
BarFilled,
Mesh,
Simple3D,
Sliced3D,
Tiled3D,
RadialFilled3D,
BarFilled3D,
Mesh3D,
};
Assembler.register(cc.Sprite, ctor);

View File

@@ -0,0 +1,101 @@
/****************************************************************************
LICENSING AGREEMENT
Xiamen Yaji Software Co., Ltd., (the “Licensor”) grants the user (the “Licensee”) non-exclusive and non-transferable rights to use the software according to the following conditions:
a. The Licensee shall pay royalties to the Licensor, and the amount of those royalties and the payment method are subject to separate negotiations between the parties.
b. The software is licensed for use rather than sold, and the Licensor reserves all rights over the software that are not expressly granted (whether by implication, reservation or prohibition).
c. The open source codes contained in the software are subject to the MIT Open Source Licensing Agreement (see the attached for the details);
d. The Licensee acknowledges and consents to the possibility that errors may occur during the operation of the software for one or more technical reasons, and the Licensee shall take precautions and prepare remedies for such events. In such circumstance, the Licensor shall provide software patches or updates according to the agreement between the two parties. The Licensor will not assume any liability beyond the explicit wording of this Licensing Agreement.
e. Where the Licensor must assume liability for the software according to relevant laws, the Licensors entire liability is limited to the annual royalty payable by the Licensee.
f. The Licensor owns the portions listed in the root directory and subdirectory (if any) in the software and enjoys the intellectual property rights over those portions. As for the portions owned by the Licensor, the Licensee shall not:
- i. Bypass or avoid any relevant technical protection measures in the products or services;
- ii. Release the source codes to any other parties;
- iii. Disassemble, decompile, decipher, attack, emulate, exploit or reverse-engineer these portion of code;
- iv. Apply it to any third-party products or services without Licensors permission;
- v. Publish, copy, rent, lease, sell, export, import, distribute or lend any products containing these portions of code;
- vi. Allow others to use any services relevant to the technology of these codes;
- vii. Conduct any other act beyond the scope of this Licensing Agreement.
g. This Licensing Agreement terminates immediately if the Licensee breaches this Agreement. The Licensor may claim compensation from the Licensee where the Licensees breach causes any damage to the Licensor.
h. The laws of the People's Republic of China apply to this Licensing Agreement.
i. This Agreement is made in both Chinese and English, and the Chinese version shall prevail the event of conflict.
****************************************************************************/
export default class FlexBuffer {
constructor (handler, index, verticesCount, indicesCount, vfmt) {
this._handler = handler;
this._index = index;
this._vfmt = vfmt;
this._verticesBytes = vfmt._bytes;
this._initVerticesCount = verticesCount;
this._initIndicesCount = indicesCount;
this.reset();
}
_reallocVData (floatsCount, oldData) {
this.vData = new Float32Array(floatsCount);
this.uintVData = new Uint32Array(this.vData.buffer);
if (oldData) {
this.vData.set(oldData);
}
this._handler.updateMesh(this._index, this.vData, this.iData);
}
_reallocIData (indicesCount, oldData) {
this.iData = new Uint16Array(indicesCount);
if (oldData) {
this.iData.set(oldData);
}
this._handler.updateMesh(this._index, this.vData, this.iData);
}
reserve (verticesCount, indicesCount) {
let floatsCount = verticesCount * this._verticesBytes >> 2;
let newFloatsCount = this.vData.length;
let realloced = false;
if (floatsCount > newFloatsCount) {
while (newFloatsCount < floatsCount) {
newFloatsCount *= 2;
}
this._reallocVData(newFloatsCount, this.vData);
realloced = true;
}
let newIndicesCount = this.iData.length;
if (indicesCount > newIndicesCount) {
while (newIndicesCount < indicesCount) {
newIndicesCount *= 2;
}
this._reallocIData(indicesCount, this.iData);
realloced = true;
}
return realloced;
}
used (verticesCount, indicesCount) {
this.usedVertices = verticesCount;
this.usedIndices = indicesCount;
this.usedVerticesFloats = verticesCount * this._verticesBytes >> 2;
this._handler.updateMeshRange(verticesCount, indicesCount);
}
reset () {
let floatsCount = this._initVerticesCount * this._verticesBytes >> 2;
this._reallocVData(floatsCount);
this._reallocIData(this._initIndicesCount);
this.usedVertices = 0;
this.usedVerticesFloats = 0;
this.usedIndices = 0;
}
}
cc.FlexBuffer = FlexBuffer

View File

@@ -0,0 +1,282 @@
/****************************************************************************
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 gfx from '../../../renderer/gfx';
let FIX_IOS14_BUFFER;
if (cc.sys.platform === cc.sys.WECHAT_GAME) {
FIX_IOS14_BUFFER = (cc.sys.os === cc.sys.OS_IOS || cc.sys.os === cc.sys.OS_OSX) && GameGlobal?.isIOSHighPerformanceMode && /(OS 1[4-9])|(Version\/1[4-9])/.test(window.navigator.userAgent);
} else {
FIX_IOS14_BUFFER = (cc.sys.os === cc.sys.OS_IOS || cc.sys.os === cc.sys.OS_OSX) && cc.sys.isBrowser && /(OS 1[4-9])|(Version\/1[4-9])/.test(window.navigator.userAgent);
}
let MeshBuffer = cc.Class({
name: 'cc.MeshBuffer',
ctor (batcher, vertexFormat) {
this.init (batcher, vertexFormat);
},
init (batcher, vertexFormat) {
this.byteOffset = 0;
this.indiceOffset = 0;
this.vertexOffset = 0;
this.indiceStart = 0;
this._dirty = false;
this._vertexFormat = vertexFormat;
this._vertexBytes = this._vertexFormat._bytes;
this._arrOffset = 0;
this._vbArr = [];
this._vb = new gfx.VertexBuffer(
batcher._device,
vertexFormat,
gfx.USAGE_DYNAMIC,
new ArrayBuffer(),
0
);
this._vbArr[0] = this._vb;
this._ibArr = [];
this._ib = new gfx.IndexBuffer(
batcher._device,
gfx.INDEX_FMT_UINT16,
gfx.USAGE_STATIC,
new ArrayBuffer(),
0
);
this._ibArr[0] = this._ib;
this._vData = null;
this._uintVData = null;
this._iData = null;
this._batcher = batcher;
this._initVDataCount = 256 * vertexFormat._bytes;// actually 256 * 4 * (vertexFormat._bytes / 4)
this._initIDataCount = 256 * 6;
this._offsetInfo = {
byteOffset : 0,
vertexOffset : 0,
indiceOffset : 0
}
this._reallocBuffer();
},
uploadData () {
if (this.byteOffset === 0 || !this._dirty) {
return;
}
// update vertext data
let vertexsData = new Float32Array(this._vData.buffer, 0, this.byteOffset >> 2);
let indicesData = new Uint16Array(this._iData.buffer, 0, this.indiceOffset);
let vb = this._vb;
vb.update(0, vertexsData);
let ib = this._ib;
ib.update(0, indicesData);
this._dirty = false;
},
switchBuffer () {
let offset = ++this._arrOffset;
this.byteOffset = 0;
this.vertexOffset = 0;
this.indiceOffset = 0;
this.indiceStart = 0;
if (offset < this._vbArr.length) {
this._vb = this._vbArr[offset];
this._ib = this._ibArr[offset];
} else {
this._vb = new gfx.VertexBuffer(
this._batcher._device,
this._vertexFormat,
gfx.USAGE_DYNAMIC,
new ArrayBuffer(),
0
);
this._vbArr[offset] = this._vb;
this._ib = new gfx.IndexBuffer(
this._batcher._device,
gfx.INDEX_FMT_UINT16,
gfx.USAGE_STATIC,
new ArrayBuffer(),
0
);
this._ibArr[offset] = this._ib;
}
},
checkAndSwitchBuffer (vertexCount) {
if (this.vertexOffset + vertexCount > 65535) {
this.uploadData();
this._batcher._flush();
this.switchBuffer();
}
},
requestStatic (vertexCount, indiceCount) {
this.checkAndSwitchBuffer(vertexCount);
let byteOffset = this.byteOffset + vertexCount * this._vertexBytes;
let indiceOffset = this.indiceOffset + indiceCount;
let byteLength = this._vData.byteLength;
let indiceLength = this._iData.length;
if (byteOffset > byteLength || indiceOffset > indiceLength) {
while (byteLength < byteOffset || indiceLength < indiceOffset) {
this._initVDataCount *= 2;
this._initIDataCount *= 2;
byteLength = this._initVDataCount * 4;
indiceLength = this._initIDataCount;
}
this._reallocBuffer();
}
this._updateOffset(vertexCount, indiceCount, byteOffset);
},
_updateOffset (vertexCount, indiceCount, byteOffset) {
let offsetInfo = this._offsetInfo;
offsetInfo.vertexOffset = this.vertexOffset;
this.vertexOffset += vertexCount;
offsetInfo.indiceOffset = this.indiceOffset;
this.indiceOffset += indiceCount;
offsetInfo.byteOffset = this.byteOffset;
this.byteOffset = byteOffset;
this._dirty = true;
},
request (vertexCount, indiceCount) {
if (this._batcher._buffer !== this) {
this._batcher._flush();
this._batcher._buffer = this;
}
this.requestStatic(vertexCount, indiceCount);
return this._offsetInfo;
},
_reallocBuffer () {
this._reallocVData(true);
this._reallocIData(true);
},
_reallocVData (copyOldData) {
let oldVData;
if (this._vData) {
oldVData = new Uint8Array(this._vData.buffer);
}
this._vData = new Float32Array(this._initVDataCount);
this._uintVData = new Uint32Array(this._vData.buffer);
let newData = new Uint8Array(this._uintVData.buffer);
if (oldVData && copyOldData) {
for (let i = 0, l = oldVData.length; i < l; i++) {
newData[i] = oldVData[i];
}
}
},
_reallocIData (copyOldData) {
let oldIData = this._iData;
this._iData = new Uint16Array(this._initIDataCount);
if (oldIData && copyOldData) {
let iData = this._iData;
for (let i = 0, l = oldIData.length; i < l; i++) {
iData[i] = oldIData[i];
}
}
},
reset () {
this._arrOffset = 0;
this._vb = this._vbArr[0];
this._ib = this._ibArr[0];
this.byteOffset = 0;
this.indiceOffset = 0;
this.vertexOffset = 0;
this.indiceStart = 0;
this._dirty = false;
},
destroy () {
this.reset();
for (let i = 0; i < this._vbArr.length; i++) {
let vb = this._vbArr[i];
vb.destroy();
}
this._vbArr = null;
for (let i = 0; i < this._ibArr.length; i++) {
let ib = this._ibArr[i];
ib.destroy();
}
this._ibArr = null;
this._ib = null;
this._vb = null;
},
forwardIndiceStartToOffset () {
this.indiceStart = this.indiceOffset;
}
});
// Should not share vb and id between multiple drawcalls on iOS14, it will cost a lot of time.
// TODO: maybe remove it after iOS14 fix it?
if (FIX_IOS14_BUFFER) {
MeshBuffer.prototype.checkAndSwitchBuffer = function (vertexCount) {
if (this.vertexOffset + vertexCount > 65535) {
this.uploadData();
this._batcher._flush();
}
};
MeshBuffer.prototype.forwardIndiceStartToOffset = function () {
this.uploadData();
this.switchBuffer();
}
}
cc.MeshBuffer = module.exports = MeshBuffer;

View File

@@ -0,0 +1,227 @@
/****************************************************************************
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 { vfmtPosUvColor, vfmt3D } = require('./vertex-format');
const QuadBuffer = require('./quad-buffer');
const MeshBuffer = require('./mesh-buffer');
const SpineBuffer = require('./spine-buffer');
const Material = require('../../assets/material/CCMaterial');
let idGenerater = new (require('../../platform/id-generater'))('VertextFormat');
import InputAssembler from '../../../renderer/core/input-assembler';
import RecyclePool from '../../../renderer/memop/recycle-pool';
import Model from '../../../renderer/scene/model';
let _buffers = {};
const empty_material = new Material();
const empty_ia = new InputAssembler();
empty_ia._count = 0;
var ModelBatcher = function (device, renderScene) {
this._renderScene = renderScene;
this._device = device;
this.walking = false;
this.material = empty_material;
this.cullingMask = 1;
this._iaPool = new RecyclePool(function () {
return new InputAssembler();
}, 16);
this._modelPool = new RecyclePool(function () {
return new Model();
}, 16);
// buffers
this._quadBuffer = this.getBuffer('quad', vfmtPosUvColor);
this._meshBuffer = this.getBuffer('mesh', vfmtPosUvColor);
this._quadBuffer3D = this.getBuffer('quad', vfmt3D);
this._meshBuffer3D = this.getBuffer('mesh', vfmt3D);
this._buffer = this._meshBuffer;
this._batchedModels = [];
this._dummyNode = new cc.Node();
this._sortKey = 0;
this.node = this._dummyNode;
this.parentOpacity = 1;
this.parentOpacityDirty = 0;
this.worldMatDirty = 0;
};
ModelBatcher.prototype = {
constructor: ModelBatcher,
reset() {
// Reset pools
this._iaPool.reset();
// Reset scene
let scene = this._renderScene;
let models = this._batchedModels;
for (let i = 0; i < models.length; ++i) {
// remove from scene
// models[i].clearInputAssemblers();
// models[i].clearEffects();
models[i].setInputAssembler(null);
models[i].setEffect(null);
scene.removeModel(models[i]);
}
this._modelPool.reset();
models.length = 0;
this._sortKey = 0;
for (let key in _buffers) {
_buffers[key].reset();
}
this._buffer = this._meshBuffer;
// reset caches for handle render components
this.node = this._dummyNode;
this.material = empty_material;
this.cullingMask = 1;
this.parentOpacity = 1;
this.parentOpacityDirty = 0;
this.worldMatDirty = 0;
},
_flushMaterial (material) {
if (!material) {
return;
}
this.material = material;
let effect = material.effect;
if (!effect) return;
// Generate model
let model = this._modelPool.add();
this._batchedModels.push(model);
model.sortKey = this._sortKey++;
model._cullingMask = this.cullingMask;
model.setNode(this.node);
model.setEffect(effect, null);
model.setInputAssembler(empty_ia);
this._renderScene.addModel(model);
},
_flush () {
let material = this.material,
buffer = this._buffer,
indiceCount = buffer.indiceOffset - buffer.indiceStart;
if (!this.walking || !material || indiceCount <= 0) {
return;
}
let effect = material.effect;
if (!effect) return;
// Generate ia
let ia = this._iaPool.add();
ia._vertexBuffer = buffer._vb;
ia._indexBuffer = buffer._ib;
ia._start = buffer.indiceStart;
ia._count = indiceCount;
// Generate model
let model = this._modelPool.add();
this._batchedModels.push(model);
model.sortKey = this._sortKey++;
model._cullingMask = this.cullingMask;
model.setNode(this.node);
model.setEffect(effect);
model.setInputAssembler(ia);
this._renderScene.addModel(model);
buffer.forwardIndiceStartToOffset();
},
_flushIA (ia) {
if (!ia) {
return;
}
let material = this.material;
let effect = material.effect;
if (!effect) return;
// Generate model
let model = this._modelPool.add();
this._batchedModels.push(model);
model.sortKey = this._sortKey++;
model._cullingMask = this.cullingMask;
model.setNode(this.node);
model.setEffect(effect);
model.setInputAssembler(ia);
this._renderScene.addModel(model);
},
terminate () {
if (cc.dynamicAtlasManager && cc.dynamicAtlasManager.enabled) {
cc.dynamicAtlasManager.update();
}
// flush current rest Model
this._flush();
for (let key in _buffers) {
_buffers[key].uploadData();
}
this.walking = false;
},
getBuffer (type, vertextFormat) {
let key = type + vertextFormat.getHash();
let buffer = _buffers[key];
if (!buffer) {
if (type === 'mesh') {
buffer = new MeshBuffer(this, vertextFormat);
}
else if (type === 'quad') {
buffer = new QuadBuffer(this, vertextFormat);
}
else if (type === 'spine') {
buffer = new SpineBuffer(this, vertextFormat);
}
else {
cc.error(`Not support buffer type [${type}]`);
return null;
}
_buffers[key] = buffer;
}
return buffer;
}
}
module.exports = ModelBatcher;

View File

@@ -0,0 +1,75 @@
/****************************************************************************
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 MeshBuffer = require('./mesh-buffer');
let QuadBuffer = cc.Class({
name: 'cc.QuadBuffer',
extends: MeshBuffer,
_fillQuadBuffer () {
let count = this._initIDataCount / 6;
let buffer = this._iData;
for (let i = 0, idx = 0; i < count; i++) {
let vertextID = i * 4;
buffer[idx++] = vertextID;
buffer[idx++] = vertextID+1;
buffer[idx++] = vertextID+2;
buffer[idx++] = vertextID+1;
buffer[idx++] = vertextID+3;
buffer[idx++] = vertextID+2;
}
let indicesData = new Uint16Array(this._iData.buffer, 0, count * 6);
this._ib.update(0, indicesData);
},
uploadData () {
if (this.byteOffset === 0 || !this._dirty) {
return;
}
// update vertext data
let vertexsData = new Float32Array(this._vData.buffer, 0, this.byteOffset >> 2);
this._vb.update(0, vertexsData);
this._dirty = false;
},
switchBuffer () {
this._super();
// upload index buffer data
let indicesData = new Uint16Array(this._iData.buffer, 0, this._initIDataCount);
this._ib.update(0, indicesData);
},
_reallocBuffer () {
this._reallocVData(true);
this._reallocIData();
this._fillQuadBuffer();
}
});
cc.QuadBuffer = module.exports = QuadBuffer;

View File

@@ -0,0 +1,72 @@
import FlexBuffer from "./flex-buffer";
import { vfmtPosUvColor } from './vertex-format';
export default function RenderData () {
this.vDatas = [];
this.uintVDatas = [];
this.iDatas = [];
this.meshCount = 0;
this._infos = null;
this._flexBuffer = null;
}
cc.js.mixin(RenderData.prototype, {
init (assembler) {
},
clear () {
this.vDatas.length = 0;
this.iDatas.length = 0;
this.uintVDatas.length = 0;
this.meshCount = 0;
this._infos = null;
if (this._flexBuffer) {
this._flexBuffer.reset();
}
},
updateMesh (index, vertices, indices) {
this.vDatas[index] = vertices;
this.uintVDatas[index] = new Uint32Array(vertices.buffer, 0, vertices.length);
this.iDatas[index] = indices;
this.meshCount = this.vDatas.length;
},
updateMeshRange (verticesCount, indicesCount) {
},
createData (index, verticesFloats, indicesCount) {
let vertices = new Float32Array(verticesFloats);
let indices = new Uint16Array(indicesCount);
this.updateMesh(index, vertices, indices);
},
createQuadData (index, verticesFloats, indicesCount) {
this.createData(index, verticesFloats, indicesCount);
this.initQuadIndices(this.iDatas[index]);
},
createFlexData (index, verticesFloats, indicesCount, vfmt) {
vfmt = vfmt || vfmtPosUvColor;
this._flexBuffer = new FlexBuffer(this, index, verticesFloats, indicesCount, vfmt);
},
initQuadIndices(indices) {
let count = indices.length / 6;
for (let i = 0, idx = 0; i < count; i++) {
let vertextID = i * 4;
indices[idx++] = vertextID;
indices[idx++] = vertextID+1;
indices[idx++] = vertextID+2;
indices[idx++] = vertextID+1;
indices[idx++] = vertextID+3;
indices[idx++] = vertextID+2;
}
}
})
cc.RenderData = RenderData;

View File

@@ -0,0 +1,42 @@
var SpineBuffer = cc.Class({
name: 'cc.SpineBuffer',
extends: require('./mesh-buffer'),
requestStatic (vertexCount, indiceCount) {
this.checkAndSwitchBuffer(vertexCount);
let byteOffset = this.byteOffset + vertexCount * this._vertexBytes;
let indiceOffset = this.indiceOffset + indiceCount;
let byteLength = this._vData.byteLength;
let indiceLength = this._iData.length;
if (byteOffset > byteLength || indiceOffset > indiceLength) {
while (byteLength < byteOffset || indiceLength < indiceOffset) {
this._initVDataCount *= 2;
this._initIDataCount *= 2;
byteLength = this._initVDataCount * 4;
indiceLength = this._initIDataCount;
}
this._reallocBuffer();
}
let offsetInfo = this._offsetInfo;
offsetInfo.vertexOffset = this.vertexOffset;
offsetInfo.indiceOffset = this.indiceOffset;
offsetInfo.byteOffset = this.byteOffset;
},
adjust (vertexCount, indiceCount) {
this.vertexOffset += vertexCount;
this.indiceOffset += indiceCount;
this.byteOffset = this.byteOffset + vertexCount * this._vertexBytes;
this._dirty = true;
}
});
cc.SpineBuffer = module.exports = SpineBuffer;

View File

@@ -0,0 +1,80 @@
/****************************************************************************
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 gfx from '../../../renderer/gfx';
var vfmt3D = new gfx.VertexFormat([
{ name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 3 },
{ name: gfx.ATTR_UV0, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
{ name: gfx.ATTR_COLOR, type: gfx.ATTR_TYPE_UINT8, num: 4, normalize: true },
]);
vfmt3D.name = 'vfmt3D';
gfx.VertexFormat.XYZ_UV_Color = vfmt3D;
var vfmtPosUvColor = new gfx.VertexFormat([
{ name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
{ name: gfx.ATTR_UV0, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
{ name: gfx.ATTR_COLOR, type: gfx.ATTR_TYPE_UINT8, num: 4, normalize: true },
]);
vfmtPosUvColor.name = 'vfmtPosUvColor';
gfx.VertexFormat.XY_UV_Color = vfmtPosUvColor;
var vfmtPosUvTwoColor = new gfx.VertexFormat([
{ name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
{ name: gfx.ATTR_UV0, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
{ name: gfx.ATTR_COLOR, type: gfx.ATTR_TYPE_UINT8, num: 4, normalize: true },
{ name: gfx.ATTR_COLOR0, type: gfx.ATTR_TYPE_UINT8, num: 4, normalize: true },
]);
vfmtPosUvTwoColor.name = 'vfmtPosUvTwoColor';
gfx.VertexFormat.XY_UV_Two_Color = vfmtPosUvTwoColor;
var vfmtPosUv = new gfx.VertexFormat([
{ name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
{ name: gfx.ATTR_UV0, type: gfx.ATTR_TYPE_FLOAT32, num: 2 }
]);
vfmtPosUv.name = 'vfmtPosUv';
gfx.VertexFormat.XY_UV = vfmtPosUv;
var vfmtPosColor = new gfx.VertexFormat([
{ name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
{ name: gfx.ATTR_COLOR, type: gfx.ATTR_TYPE_UINT8, num: 4, normalize: true },
]);
vfmtPosColor.name = 'vfmtPosColor';
gfx.VertexFormat.XY_Color = vfmtPosColor;
var vfmtPos = new gfx.VertexFormat([
{ name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
]);
vfmtPos.name = 'vfmtPos';
gfx.VertexFormat.XY = vfmtPos;
module.exports = {
vfmt3D,
vfmtPosUvColor,
vfmtPosUvTwoColor,
vfmtPosUv,
vfmtPosColor,
vfmtPos
};