mirror of
https://github.com/smallmain/cocos-enhance-kit.git
synced 2026-01-11 17:16:53 +00:00
初始化
This commit is contained in:
163
engine/cocos2d/core/renderer/assembler-2d.js
Normal file
163
engine/cocos2d/core/renderer/assembler-2d.js
Normal 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;
|
||||
47
engine/cocos2d/core/renderer/assembler-3d.js
Normal file
47
engine/cocos2d/core/renderer/assembler-3d.js
Normal 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;
|
||||
86
engine/cocos2d/core/renderer/assembler-pool.js
Normal file
86
engine/cocos2d/core/renderer/assembler-pool.js
Normal 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;
|
||||
50
engine/cocos2d/core/renderer/assembler.js
Normal file
50
engine/cocos2d/core/renderer/assembler.js
Normal 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;
|
||||
94
engine/cocos2d/core/renderer/canvas/Device.js
Normal file
94
engine/cocos2d/core/renderer/canvas/Device.js
Normal 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;
|
||||
41
engine/cocos2d/core/renderer/canvas/Texture2D.js
Normal file
41
engine/cocos2d/core/renderer/canvas/Texture2D.js
Normal 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;
|
||||
41
engine/cocos2d/core/renderer/canvas/forward-renderer.js
Normal file
41
engine/cocos2d/core/renderer/canvas/forward-renderer.js
Normal 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;
|
||||
34
engine/cocos2d/core/renderer/canvas/index.js
Normal file
34
engine/cocos2d/core/renderer/canvas/index.js
Normal 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
|
||||
};
|
||||
@@ -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;
|
||||
46
engine/cocos2d/core/renderer/canvas/render-flow.js
Normal file
46
engine/cocos2d/core/renderer/canvas/render-flow.js
Normal 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');
|
||||
}
|
||||
159
engine/cocos2d/core/renderer/canvas/renderers/graphics/impl.js
Normal file
159
engine/cocos2d/core/renderer/canvas/renderers/graphics/impl.js
Normal 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;
|
||||
@@ -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);
|
||||
34
engine/cocos2d/core/renderer/canvas/renderers/index.js
Normal file
34
engine/cocos2d/core/renderer/canvas/renderers/index.js
Normal 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';
|
||||
117
engine/cocos2d/core/renderer/canvas/renderers/label/bmfont.js
Normal file
117
engine/cocos2d/core/renderer/canvas/renderers/label/bmfont.js
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
76
engine/cocos2d/core/renderer/canvas/renderers/label/index.js
Normal file
76
engine/cocos2d/core/renderer/canvas/renderers/label/index.js
Normal 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
|
||||
});
|
||||
90
engine/cocos2d/core/renderer/canvas/renderers/label/ttf.js
Normal file
90
engine/cocos2d/core/renderer/canvas/renderers/label/ttf.js
Normal 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;
|
||||
}
|
||||
}
|
||||
45
engine/cocos2d/core/renderer/canvas/renderers/mask.js
Normal file
45
engine/cocos2d/core/renderer/canvas/renderers/mask.js
Normal 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);
|
||||
22
engine/cocos2d/core/renderer/canvas/renderers/render-data.js
Normal file
22
engine/cocos2d/core/renderer/canvas/renderers/render-data.js
Normal 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,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
155
engine/cocos2d/core/renderer/canvas/renderers/sprite/simple.js
Normal file
155
engine/cocos2d/core/renderer/canvas/renderers/sprite/simple.js
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
175
engine/cocos2d/core/renderer/canvas/renderers/sprite/sliced.js
Normal file
175
engine/cocos2d/core/renderer/canvas/renderers/sprite/sliced.js
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
183
engine/cocos2d/core/renderer/canvas/renderers/utils.js
Normal file
183
engine/cocos2d/core/renderer/canvas/renderers/utils.js
Normal 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;
|
||||
188
engine/cocos2d/core/renderer/index.js
Normal file
188
engine/cocos2d/core/renderer/index.js
Normal 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();
|
||||
}
|
||||
};
|
||||
287
engine/cocos2d/core/renderer/render-flow.js
Normal file
287
engine/cocos2d/core/renderer/render-flow.js
Normal 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;
|
||||
140
engine/cocos2d/core/renderer/utils/dynamic-atlas/atlas.js
Normal file
140
engine/cocos2d/core/renderer/utils/dynamic-atlas/atlas.js
Normal 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;
|
||||
267
engine/cocos2d/core/renderer/utils/dynamic-atlas/manager.js
Normal file
267
engine/cocos2d/core/renderer/utils/dynamic-atlas/manager.js
Normal 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;
|
||||
689
engine/cocos2d/core/renderer/utils/label/bmfont.js
Normal file
689
engine/cocos2d/core/renderer/utils/label/bmfont.js
Normal file
@@ -0,0 +1,689 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
https://www.cocos.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
import 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 () {}
|
||||
}
|
||||
118
engine/cocos2d/core/renderer/utils/label/label-frame.js
Normal file
118
engine/cocos2d/core/renderer/utils/label/label-frame.js
Normal 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;
|
||||
313
engine/cocos2d/core/renderer/utils/label/letter-font.js
Normal file
313
engine/cocos2d/core/renderer/utils/label/letter-font.js
Normal 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;
|
||||
}
|
||||
}
|
||||
545
engine/cocos2d/core/renderer/utils/label/ttf.js
Normal file
545
engine/cocos2d/core/renderer/utils/label/ttf.js
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
53
engine/cocos2d/core/renderer/utils/utils.js
Normal file
53
engine/cocos2d/core/renderer/utils/utils.js
Normal 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
|
||||
}
|
||||
669
engine/cocos2d/core/renderer/webgl/assemblers/graphics/earcut.js
Normal file
669
engine/cocos2d/core/renderer/webgl/assemblers/graphics/earcut.js
Normal 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;
|
||||
};
|
||||
217
engine/cocos2d/core/renderer/webgl/assemblers/graphics/impl.js
Normal file
217
engine/cocos2d/core/renderer/webgl/assemblers/graphics/impl.js
Normal 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;
|
||||
703
engine/cocos2d/core/renderer/webgl/assemblers/graphics/index.js
Normal file
703
engine/cocos2d/core/renderer/webgl/assemblers/graphics/index.js
Normal 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);
|
||||
32
engine/cocos2d/core/renderer/webgl/assemblers/index.js
Normal file
32
engine/cocos2d/core/renderer/webgl/assemblers/index.js
Normal 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');
|
||||
180
engine/cocos2d/core/renderer/webgl/assemblers/label/2d/bmfont.js
Normal file
180
engine/cocos2d/core/renderer/webgl/assemblers/label/2d/bmfont.js
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
101
engine/cocos2d/core/renderer/webgl/assemblers/label/2d/ttf.js
Normal file
101
engine/cocos2d/core/renderer/webgl/assemblers/label/2d/ttf.js
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
98
engine/cocos2d/core/renderer/webgl/assemblers/label/index.js
Normal file
98
engine/cocos2d/core/renderer/webgl/assemblers/label/index.js
Normal 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
|
||||
});
|
||||
195
engine/cocos2d/core/renderer/webgl/assemblers/mask-assembler.js
Normal file
195
engine/cocos2d/core/renderer/webgl/assemblers/mask-assembler.js
Normal 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);
|
||||
271
engine/cocos2d/core/renderer/webgl/assemblers/motion-streak.js
Normal file
271
engine/cocos2d/core/renderer/webgl/assemblers/motion-streak.js
Normal 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);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
148
engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/mesh.js
Normal file
148
engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/mesh.js
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
});
|
||||
349
engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/tiled.js
Normal file
349
engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/tiled.js
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -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);
|
||||
101
engine/cocos2d/core/renderer/webgl/flex-buffer.js
Normal file
101
engine/cocos2d/core/renderer/webgl/flex-buffer.js
Normal 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 Licensor’s 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 Licensor’s 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 Licensee’s 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
|
||||
282
engine/cocos2d/core/renderer/webgl/mesh-buffer.js
Normal file
282
engine/cocos2d/core/renderer/webgl/mesh-buffer.js
Normal 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;
|
||||
227
engine/cocos2d/core/renderer/webgl/model-batcher.js
Normal file
227
engine/cocos2d/core/renderer/webgl/model-batcher.js
Normal 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;
|
||||
75
engine/cocos2d/core/renderer/webgl/quad-buffer.js
Normal file
75
engine/cocos2d/core/renderer/webgl/quad-buffer.js
Normal 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;
|
||||
72
engine/cocos2d/core/renderer/webgl/render-data.js
Normal file
72
engine/cocos2d/core/renderer/webgl/render-data.js
Normal 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;
|
||||
|
||||
42
engine/cocos2d/core/renderer/webgl/spine-buffer.js
Normal file
42
engine/cocos2d/core/renderer/webgl/spine-buffer.js
Normal 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;
|
||||
80
engine/cocos2d/core/renderer/webgl/vertex-format.js
Normal file
80
engine/cocos2d/core/renderer/webgl/vertex-format.js
Normal 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
|
||||
};
|
||||
Reference in New Issue
Block a user